How to initialize derived class member in case of multiple inheritance [duplicate] - c++

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) {}

Related

multiple inheritance diamond problem without default constructor

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.

Constructor calling flow in virtual inheritance? [duplicate]

class A {
int i;
public:
A() {cout<<"in A's def const\n";};
A(int k) {cout<<"In A const\n"; i = k; }
};
class B : virtual public A {
public:
B(){cout<<"in B's def const\n";};
B(int i) : A(i) {cout<<"in B const\n";}
};
class C : public B {
public:
C() {cout<<"in C def cstr\n";}
C(int i) : B(i) {cout<<"in C const\n";}
};
int main()
{
C c(2);
return 0;
}
The output in this case is
in A's def const
in B const
in C const
Why is this not entering into in A const
`It should follow the order of 1 arg constructor call.
But what actually is happening on deriving B from A using virtual keyword.
There are few more question
Even if I remove the virtual keyword in above program and remove all the default constructor it gives error. So, why it needs the def constructor
The constructors for virtual base classes are always called from the most derived class, using any arguments it might pass in. In your case, the most derived class doesn't specify an initializer for A, so the default constructor is used.
As JamesKanze has explained, in case of virtual inheritance it is the most derived class that calls the virtual base class' constructor. So, if you want A's constructor that takes an integer to be called, you need to add that to C's initialization list.
C(int i) : A(i), B(i) {cout<<"in C const\n";}
For the second part of your question, default constructors are not required, but then the derived class must call the non-default constructor explicitly, since the compiler is unable to do that for you in the absence of a non-default constructor.
#include <iostream>
using namespace std;
class A {
int i;
public:
// A() {cout<<"in A's def const\n";};
A(int k) {cout<<"In A const\n"; i = k; }
};
class B : virtual public A {
public:
// B(){cout<<"in B's def const\n";};
B(int i) : A(i) {cout<<"in B const\n";}
};
class C : public B {
public:
C() : A(42), B(42) {cout<<"in C def cstr\n";}
C(int i) : A(i), B(i) {cout<<"in C const\n";}
};
int main()
{
C c(2), c2;
return 0;
}
This prints out
In A const
in B const
in C const
In A const
in B const
in C def cstr
There are two questions here.
Why is this not entering into in A const?
Because you are using virtual inheritance.
When you use virtual inheritance, the Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.. In this case, that means that C's constructor calls A's constructor directly. Since you have not specified which A constructor to call in C's initialization list, the default constructor is called.
This is fixed by changing your implementation of C::C(int) to:
C(int i) : A(i), B(i) {cout<<"in C const\n";}
If I remove the virtual keyword in above program and remove all the
default constructor it gives error. So, why it needs the def
constructor?
Because B also doesn't specify which A ctor to call, so the default constructor is used. If you remove As def ctor, B can't be compiled.

C++ delegating ctor and parent ctor with argument

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.

Inhereting constructors in C++ [duplicate]

This question already has an answer here:
Why is Default constructor called in virtual inheritance?
(1 answer)
Closed 9 years ago.
C++11 standard provides a way to inherit constructors from the base class. My question is regarding earlier standards. Suppose I inherit constructors in the following way:
class Base {
public:
Base() {};
Base(int b) { a = ++b;}
virtual int foo() {return 0;}
int a;
};
class A : public virtual Base {
public:
A() {}
A(int b): Base(b) {}
int foo() {return a*a;}
};
class C : public A {
public:
C() {}
C(int b ): A(b) {}
int foo() { return (a*a + a);}
};
Note that I am having virtual inheritance of the Base class. Now when I try to initialize a pointer to an object of type C then instead of calling Base(b) constructor, the code ends up calling Base() constructor. Here is the main function that I used:
int main(){
C *c = new C(5);
std::cout << c->Base::a << std::endl;
}
The output value of "a" is 0. However, when I remove the virtual keyword while inheriting the Base class, then Base(b) constructor is called and the value of "a" is 6. Can someone help me in understanding what is going on? Why is it that with virtual inheritance default constructor is called?
Virtual base classes are initialised based on the member initialiser list of the constructor of the most derived class.
In your case, when you're creating an instance of C, its Base subobject will be initialised based on the member-initialiser list in C's constructor; and since Base is not listed there, it will be default-initialised.
If you were creating an instance of A, then indeed A's member-initialiser list would be used.
So to call the Base constructor which you want, you'd have to modify C's constructor like this:
C(int b ): A(b), Base(b) {}

Constructor call hierarchy

I'm having a tricky time with calling rules for constructors in a type hierarchy. Here is what I do:
class A{
protected:
int _i;
public:
A(){i = 0;}
A(int i) : _i(i){}
virtual ~A(){}
virtual void print(){std::cout<<i<<std::endl;}
};
class B : virtual public A{
protected:
int _j;
public:
B() : A(){_j = 0;}
B(int i, int j) : A(i), _j(j){}
virtual ~B(){}
virtual void print(){std::cout<<i<<", "<<j<<std::endl;}
};
class C : virtual public B{
protected:
int _k;
public:
C() : B(){_k = 0;}
C(int i, int j, int k} : B(i,j), _k(k){}
virtual ~C(){}
virtual void print(){std::cout<<i<<", "<<j<<", "<<k<<std::endl;}
};
int main(){
C* myC = new C(1,2,3);
myC->print();
delete myC;
return 0;
}
Now, I would like to have new C(1,2,3) call the constructor of B(1,2) which then in turn should call the constructor A(1) to store _i=1, _j=2, _k=3. When creating the instance myC of the class C, for some reason I don't understand, however, the first constructor to be called is the standard constructor of A, i.e., A::A(); This obviously leads to wrong results, as the protected variable _i is assigned the value 0. The constructor A(1) is never called. Why is this so? I find this very counter intuitive. Is there some way to avoid explicitly calling all constructors within the type-hierarchy to achieve the desired behavior?
Thx for the help!
do you really need a virtual inheritance here?
you've got a problem because a very first virtual base ctor will be called first, but you don't specify any when inherit C from B (latter already have A virtually inherited, so default was called).
one solution is to remove virtual inheritance... as mentioned in the answer of Arne Mertz.
another (if you really want virtual inheritance) is to call A explicitly from C ctor:
C(int i, int j, int k} : A(i), B(i,j), _k(k){}
When you use virtual inheritance, the most derived class must call the constructors for all its virtual bases directly. In this case, the constructor for C must call the constructors for B and A. Since you only call the B constructor, it uses the default A constructor. It does not matter that the B constructor calls another A constructor: since it is a virtual base class, this call is ignored.
You have two ways around this problem: explicitly call the A(int) constructor:
C(int i, int j, int k} : A (i), B(i,j), _k(k){}
or use normal inheritance instead of virtual.
This is because you used virtual inheritance, which makes only sense in the presence of multiple inheritances. Just inherit normally, and all will be as you expect it.
Why do you declare virtual inheritance? If you remove virtual keyword from class B: virtual public A { ... then your code will work fine. By declaring virtual A, C will call A() directly. If you remove virtual then C will not call A().