This does not seem to work in C++11:
class B : public A
{
public:
B(const A& a)
: A(a) // parent constructor for passing the parameter
, B() // delegating constructor for init of other members
{};
// ...
};
gcc tells me that an initializer for a delegating constructor must appear alone.
How do I both call the constructor of the parent class with the parameter, and call the basic constructor of the B class? (I have a bunch of other constructors in B that need the same behavior).
Right now I am considering writing a private B::init() function and use it in all constructor bodies, but that tastes a bit much of C++03.
What is the preferred solution?
I believe the preferred way of delegation is the other way around, it's not meant to be used to refactor common parts of constructors, but rather to define the simpler one as a special case of a the more complex case.
So you should start with B(const A& a) and use this as delegation target.
class B : public A
{
public:
B() : B(A());
B(const A& a) : A(a) // parent constructor for passing the parameter
{};
};
You are calling A() anyways when creating B.
The rationale behind it is when you have two "partially specialized" c'tors, you wouldn't be able to use them to initialize the complex one. E.g:
class B : public A
{
public:
B() {};
B(int) : B() {};
B(double) : B() {};
B(double,int) : B(int), B(double) {}; // can't do it.
};
I believe the technical reason is explained in Bathsheba's answer. Look what would happen if you had a common part in B():
class B : public A
{
public:
B() {};
B(int) : B() {};
B(double) : B() {};
B(double,int) : B(int), B(double) {}; //ooops would get B() called twice!
};
It's the diamond problem known from inheritance. The solution is to reverse the logic.
class B : public A
{
public:
B() : B(0,0) {};
B(int a) : B(a,0) {};
B(double d) : B(0,d) {};
B(double a, int d) {/*full implementation*/};
};
B(const A& a) : A(a), B() does not make sense since B() will also initialise the base class A. That would essentially be a duplicate initialisation, which is an inherent contradiction.
The only real option for the language is to disallow anything else if you use a delegated constructor. That's what your compiler is telling you.
Related
I have a base class that holds a vector of pointers to derived classes and a virtual recursive method like this:
class Base
{
std::vector<Base*> vec;
public:
Base(std::vector<Base*> vec = {}) : vec {vec} {}
virtual ~Base() = default;
virtual void f() const
{
if (vec.size() == 0)
throw std::logic_error("Last children should implement f()")
for (auto * part : vec)
part->f();
}
}
The method f() is recursive and the last child of Base should override it. For example the following works
Where the first derived class is
class B : public Base
{
B() : Base() {}
virtual void f() const
{
std::cout << "In B\n";
}
}
class A : public Base
{
B b_,c_;
public:
A(B b, B c) : Base({&b_,&c_}), b_ {b}, c_{c} {}
}
If I call
B b,c;
A a(b,c);
a.f()
It will print twice "In B"correctly. Notice that A does not override f() so Base::f() is called, this loops and calls B::f() twice, once for b and once for c. However if I go one nested class more, for example by having
class C : public Base
{
A a_;
B b_;
public:
C(A a, B b): Base({&a_, &b_}), a_{a}, b_{b} {}
}
And I call C::f() the program segfaults. I suppose this is because there are some temporaries and their destructors delete the pointers held by Base. Is the solution to this to hold shared_ptr? or is there a better design? I cannot hold unique_ptr cause that would make all derived classes not copyable.
public C(A a, B b): Base({&a, &b}), a{a}, b{b} {}
Firstly, you can't have public there.
Your base points to the parameters of the constructor. Those parameters are destroyed when the constructor finishes and the pointers become invalid. Point to the members instead:
C(A a, B b): Base({&this->a, &this->b}), a{a}, b{b} {}
Note however that the implicit copy and move constructors and assignment operators of the class are broken because they will make the copied object point to the members of the copy source, rather than the members of the copy itself. So, you'll need implement those as well.
is there a better design?
Possibly a better approach: Instead of storing the pointers in the base sub object, write a virtual function that derived classes can override, and which returns a range of pointers to children.
I end up with a multiple inheritance diamond problem with the situation that there is no default constructor in the base class.
struct A {
A(int x) {}
};
struct B : virtual public A {
using A::A;
};
struct C : virtual public A {
using A::A;
};
struct D : virtual public B, public C {
D(int x) : B(x), C(x) {}
};
int main() {
D d(1);
}
The compiler is complaining that:
error: constructor for 'D' must explicitly initialize the base
class 'A' which does not have a default constructor
D(int x) : B(x), C(x) {}
But, I don't really have access to A from D... How can I fix that? Thanks
You do have an access to A since you're inheriting from it.
You would have to call the constructor of A in order to construct the object D.
Your D constructor should look something like that :
D(int x) : A(x), B(x), C(x) {}
Because of the multiple inheritance, constructors of B and C would ignore the A(x) part and you will have only one object which is D.
Following explanation and examples from here I have exemplary constructed the following inheritance model creating a diamond
class Base {
public:
int data_;
Base(int d) : data_(d) {}
Base() = deleted;
};
class A : public virtual Base {
public:
A() : Base(42) {};
};
class B : public virtual Base {
public:
B() : Base(24) {};
}
class AB : public A, public B {
public:
AB() : Base(-1) {};
}
so far so good; note, that AB() needs to call to the Base(int)-ctor now. This is kind of understandable, because having the alternative initializer branches of going through AB>>A>>Base or AB>>B>>Base would not result in a well defined behavior at that.
Lets branch out from class A into a side-branch before we even have closed the diamond:
class A_Child : public A {
public:
A_Child() : A() {}; // not permitted by compiler
}
This will not compile, as the compiler will explicitly ask for to specify the ctor Base(int) in the inializer list of A_Child.
I don't quite understand this behavior; as we are no longer virtually inheriting at this point and the path of initalization of A_Child>>A>>Base is not ambiguous.
It seems now for every furthermore derived class of A_Child I have to again specify the Base(int) initializer explicitly. This is kind of breaking the encapsulation as every code that derives from this class needs to know how the class at the very base acts and is implemented.
Is there any way to stop or to break the virtual inheritance once I branch into a side-line?
Is possible to have virtual inheritance for class not providing default constructor?
The present diamond diagram (the simplest one with the only change of no default constructor provided) does not compile (g++ 4.4.3).
class A {
public:
A(int ) {}
};
class B : virtual public A {
public:
B(int i) : A(i) {}
};
class C : virtual public A {
public:
C(int i) : A(i) {}
};
class D : public B, public C {
public:
D(int i) : B(i), C(i) {}
};
Thanks,
Francesco
You need to call A's constructor explicitly here
D(int i) : A(i), B(i), C(i) {}
virtual base classes are special in that they are initialized by the most derived class and not by any intermediate base classes that inherits from the virtual base. Which of the potential multiple initializers would the correct choice for initializing the one base?
If the most derived class being constructed does not list it in its member initalization list then the virtual base class is initialized with its default constructor which must exist and be accessible.
Shamelessly copied from here :-)
I believe your class D also needs to explicitly call A's constructor in its initializer list.
The Dr. Dobbs article Multiple Inheritance Considered Useful explains various ways of dealing with this. The recommendation is basically to provide default constructors and init() methods. It adds more work for B and C but prevents D from having to know about A.
you need explict call A's construct like this:
D(int i) : A(i), B(i), C(i) {}
I'm currently trying to build a hierarchy of classes that uses multiple inheritance. I have classes A, B, C and D, related as such:
struct A
{
int a;
A(int a_) : a(a_) {}
};
struct B : virtual A
{
int b;
B(int a_, int b_) : A(a_), b(b_) {}
};
struct C : virtual A
{
C(int a_) : A(a_) {}
};
struct D : B , C
{
D(int a_, int b_) : A(a_), B(a_, b_) , C(a_) {}
};
My problem is that D is passing arguments to B and C that aren't needed, and I'd like to find a better way of doing this.
The best way I found would be to have D initialize B first with B(a_, b_) and then B would initialize A with A(a_) and then I'd initialize C with C(a_) (even though the argument wouldn't matter) and 'link' C's instance of A to B's A instance.
What I mean by this is that the memory layout of D would look something like this:
Where C's base class A would be located inside of B.
I've tried multiple ways to do this in C++, but I haven't found one where it would let me change where C's A was located nor do I know if it possible.
My question is if this is possible to achieve in C++ using inheritance or possibly another tool?
Even if it possible, I would still have the problem of having to initialize both B and C with a 'dummy' argument that wouldn't do anything, this is fine for an int, but not for something more 'heavy'.
What I would want is for, when inheriting from B or C, you'd use an empty constructor to initialize it, and would use the other constructor when creating it normally, something like this:
struct A
{
int a;
A(int a_) : a(a_) {}
};
struct B : virtual A
{
int b;
B(int a_, int b_) : A(a_), b(b_) {}
protected:
// The A initialization will never get called
B(int b_) : A(0), b(b_) {}
};
struct C : virtual A
{
C(int a_) : A(a_) {}
protected:
// This initialization will never get called
C() : A(0) {}
};
struct D : B , C
{
D(int a_, int b_) : A(a_), B(b_) , C() {}
};
The only problem is that I'm not sure this has any side effects I should be aware of, or if it even works, I couldn't think of a way to test it well.
I'm not sure if asking two questions in one is acceptable, I believe that they make sense together, but if not, I'll edit it out and ask it as a different question.
Edit 1:
In relation to the duplicate, that answer states that the unused arguments will not be used to initialize the base-most class in the two derived classes.
My second question is how can I avoid having to provide the unused parameters to the two derived classes as the arguments can be very big and take a long time and memory copying. I have provided a possible solution, but I am not sure if this actually solves my problem and what side effects it can have.
Thus more concretely, my second question is Is this implementation of avoiding providing the parameters to the two derived classes good or are there any side effects I haven't taken in to account while building it?