Problem
I am looking for the best way to define the variables in parent-child classes, in order to be called by a pointer to their parent class.
This is the protocode:
class Base {
public:
virtual void function() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
class B : public Base {
public:
int a, b;
B(int a_, int b_) : a(a_), b(b_) {};
void function() { // do something.. }
};
Base* elements[2] = {
new A(1,2),
new B(3,4)
};
Since I define a, b in both constructors, I might define them in the abstract class Base. This way the code should be more efficient and clean. Is this practice correct? How should I define them?
Possible solutions
The solution I have in mind is implementing a function that returns for example a like this:
class Base {
public:
virtual int return_a() = 0;
};
class A : public Base {
public:
int a, b;
A(int a_, int b_) : a(a_), b(b_) {};
int return_a() {
return a;
}
};
int main(){
int a = elements[0]->return_a();
}
This works, but I am sure it is not an efficient way. Is it better to define a, b in the abstract class? Thanks
Is this practice correct?
I think this is turning into an opinion-based question-answer. If all your derived classes must include the members a and b, then in my opinion, they should be part of the base class. This way, you are guaranteed that all your derived classes will include the members a and b and you (or someone else) won't run the risk of forgetting to include them. Furthermore, by including the members in the base class, you save memory by not having to include them at every single derived class. C++'s virtual provides you with all the necessary tools to accomplish polymorphism, which is what happens when you create an array of Base *.
I would also recommend you use the keyword override for the virtual functions that are overridden in the derived class, and the keyword final for the derived classes that are not meant to become base classes. You can read the benefits of using those keywords from Scott Meyers Modern C++ book.
struct Base
{
int a, b;
Base(int a_, int b_) : a(a_) , b(b_)
{;}
virtual void function() = 0;
};
struct A : Base // A can be a base class of another class.
{
A(int a_, int b_) : Base(a_,b_)
{;}
void funtion() // this will compile, but it's not going to override the Base::function()
{;}
};
struct B final : Base // B can never become a base class.
{
B(int a_, int b_) : Base(a_,b_)
{;}
void funtion() override // this won't compile because override will see that we mis-spelled function()
{;}
};
However, there is no C++ rule that prohibits you from including the members in all of your derived classes.
Also, if all your members are public, then you can use a struct to avoid having to type public inside the classes and in the inheritance method.
struct Base
{
// all members are public
};
struct Derived : Base // public inheritance by default.
{
// all members are public
};
This is somewhat opinion based, but here is what I think based on the code you have posted.
Since you have made Base (from which all classes are derived) an abstract class, it appears that you want to use it as an interface.
In that case, it is better to distinguish between interface inheritance and implementation inheritance. Let Base not have any data which means that it would not require any constructors.
This is one of the coding guidelines given by Bjarne Stroustrup titled: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance.
The reason given is:
Implementation details in an interface make the interface brittle; that is, make its users vulnerable to having to recompile after changes in the implementation. Data in a base class increases the complexity of implementing the base and can lead to replication of code.
Note that you do not need getters or setters if the data in derived classes is public.
Related
Based on what I’ve read, it seems the memory for derived objects is made sequentially with the base class and all its data made first and then immediately followed by the following classes down the inheritance tree. So if I make a base class pointer that is equal to a new derived class object, and then increment it by one(which will actually add the size of the base class to the address), then will I arrive at the derived class? If so, can I then access the derived class’s data in this way?
Yes, and no. In the very simplest case it will work in most cases:
class Base {
public:
int v;
};
class Derived : public Base {
public:
int b;
};
int main() {
Derived d;
Base* p = &d;
p++;
// these will match on all compilers I'm aware of
printf("%p %p\n", p, &d.b);
return 0;
}
For single inheritance, that is typically what you'll see from most compilers (although I'd be very worried actually relying on that in production code!)
However, sadly things aren't always that simple! In C++ we often have multiple inheritance, virtual inheritance, abstract base classes and all those bits of goodness. So here is a scenario where it would absolutely not work!
struct Animal {
virtual ~Animal() = default;
virtual void Eat() {}
int a;
};
struct Mammal: Animal {
virtual void Breathe() {}
int b;
};
struct WingedAnimal: Animal {
virtual void Flap() {}
int c;
};
// A bat is a winged mammal
struct Bat: Mammal, WingedAnimal {
int d;
};
There are however far safer approaches to handling upcasting (e.g. dynamic_cast, or your own RTTI system). You probably will want to be using those :)
I know that it is not possible to have an instance of an abstract class as a base member of another class, i.e.,
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
virtual int yield() = 0;
};
class C1: public Base {
public:
C1(): Base() {};
virtual ~C1() {};
virtual int yield() {return 1;};
};
class D {
public:
D(Base & b): b_(b) {};
virtual ~D() {};
private:
Base b_;
}
int main() {
C1 c;
D d(c);
}
will fail to compile with the error
test.cpp:22:10: error: cannot declare field ‘D::b_’ to be of abstract type ‘Base’
The obvious workaround is to use (shared) pointers instead. This, however, makes main somewhat more complicated to read,
int main() {
auto c = std::make_shared<C1>();
D d(c);
}
which I would really like to avoid.
Is there a way to keep the main file as simple as in the above example and still achieve the desired functionality?
You can't. When you are creating D it allocates (in heap or in stack) memory for B. And C1 class needs size of base class B plus size of extra variables/etc in C1 itself even if there are nothing new.
So, use pointers instead.
The error caused by virtual int yield() = 0;. If you use virtual int yield(), it will works. When you used virtual int yield() = 0;, it said that the function is a pure virtual function, so you must override it. So you should give its inheritance class and use the instance of inheritance class in class C1. In a world, virtual int yield() = 0; only remind you that it is only a interface, you must override it. I hope this can help you.
Since Base is an abstract class (has at least one pure virtual function), it can't be instantiated directly.
When you declare D's class member as "Base b_", you are effectively trying to create an instance. You can instead use a pointer there (or some kind of safe/smart pointer).
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
virtual int yield() = 0;
};
class C1: public Base {
public:
C1(): Base() {};
virtual ~C1() {};
virtual int yield() {return 1;};
};
class D {
public:
D(Base * b): b_(b) {};
virtual ~D() {};
private:
Base *b_; // Use a pointer or safe ptr or something of that sort.
}
int main() {
C1 c;
D d(&c);
}
No. One of the properties of an abstract class is that it cannot be instantiated. That means an instance of an abstract class cannot be a member of another class.
Even if Base was not abstract, your class D's constructor would be slicing the object passed. If passed an instance of C1, the copying (in the initialiser list of D's constructor) would not magically cause an instance of D to contain an object of type C. It would instead create a copy only of the Base part of that object.
In short, your design is broken, and will not work even if - syntactically - it would be possible to simplify the code in main().
I have a base class that I'd like to prevent inheritance by most classes, but allow it for a handful of classes that I can hard code in. Is this possible in C++? Is it easier with C++11?
I thought perhaps I'd use the final argument, but that prevents any inheritance at all.
// This can be derived by anyone
class Base{
...
}
// This should only be derived by those I say can derive it
class Base2: public Base{
protected:
int SpecialVar;
}
The reason I want this is that some classes need to have access to SpecialVar while it doesn't make sense for the other classes. It still makes sense for all classes to have the functionality of Base.
Instead of making your derived classes friends, another way (that may or may not make sense, depending on the concrete classes you're dealing with), is to nest them.
class Base {
Base() { }
public:
class Derived;
};
class Base::Derived : Base {
};
class CannotDerive : Base {
};
int main() {
Base::Derived x; // ok
CannotDerive y; // error
}
class X
{
private:
X() {}
friend class D;
};
class D: public X
{
};
class Y: public X // will fail, because it can't access X::X()
{
};
Other possibility is with a private destructor (specially if A is an abstract class, since you don't need instances of A):
class A
{
private:
virtual ~A() = 0;
};
A::~A() {}
class B : public A // Compilation error: ~A() is private.
{};
However, if B is one of your classes with permission to inherit from A, make it friend of A:
class A
{
private:
friend class B;
virtual ~A() = 0;
};
A::~A() {}
class B : public A // Fine.
{};
What is the difference between:
a)
class base{
int a;
public:
virtual int function();
};
class derived : public base{
int b;
public:
int function();
};
b)
class base{
int a;
public:
int function();
};
class derived : public base{
int b;
public:
int function();
};
Why would you use (a) and why would you use (b)?
Is (b) a kind of polymorphism?
a) overrides the method in the base class. b) hides it. b) is not polymorphism.
Here's a useful link: The Definitive C++ Book Guide and List
First is overidding while second is method hiding.
First is used for dynamic dispatch and dynamic polymorphism. i.e: To call appropriate method depending on actual type of the object at run-time.
Second is used for method hiding.
Good Read:
What's the meaning of, Warning: Derived::f(char) hides Base::f(double)?
I am trying to figure out an interesting multiple inheritance issue.
The grandparent is an interface class with multiple methods:
class A
{
public:
virtual int foo() = 0;
virtual int bar() = 0;
};
Then there are abstract classes that are partially completing this interface.
class B : public A
{
public:
int foo() { return 0;}
};
class C : public A
{
public:
int bar() { return 1;}
};
The class I want to use inherits from both of the parents and specifies what method should come from where via using directives:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
};
When I try to instantiate a D I get errors for trying to instantiate an abstract class.
int main()
{
D d; //<-- Error cannot instantiate abstract class.
int test = d.foo();
int test2 = d.bar();
return 0;
}
Can someone help me understand the problem and how to best make use of partial implementations?
You don't have diamond inheritance. The B and C base classes of D each have their own A base class subobject because they do not inherit virtually from A.
So, in D, there are really four pure virtual member functions that need to be implemented: the A::foo and A::bar from B and the A::foo and A::bar from C.
You probably want to use virtual inheritance. The class declarations and base class lists would look like so:
class A
class B : public virtual A
class C : public virtual A
class D : public B, public C
If you don't want to use virtual inheritance then you need to override the other two pure virtual functions in D:
class D : public B, public C
{
public:
using B::foo;
using C::bar;
int B::bar() { return 0; }
int C::foo() { return 0; }
};
You need to make your base classes virtual in order for them to inherit properly. The general rule is that all non-private member functions and base classes should be virtual UNLESS you know what you're doing and want to disable normal inheritance for that member/base.