Order of constructor call in virtual inheritance - c++

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.

Related

Why is constructor of a grand parent deleted in this case?

The compiler is complaining the constructor of D is deleted because of ill forming why ?
#include<iostream>
using namespace std;
class A
{
int x;
public:
A(int i) { x = i; }
void print() { cout << x; }
};
class B: virtual public A
{
public:
B():A(10) { }
};
class C: virtual public A
{
public:
C():A(10) { }
};
class D: public B, public C {
};
int main()
{
D d;
d.print();
return 0;
}
Output
main.cpp:37:4: error: use of deleted function 'D::D()' D d;
^ main.cpp:32:7: note: 'D::D()' is implicitly deleted because the default definition would be ill-formed: class D: public B, public C {
^
Due to the rules for initialization of virtual base classes,
class D: public B, public C {
};
is equivalent to:
class D: public B, public C {
public:
D() : A(), B(), C() {}
};
That's why you cannot create in instance of D.
Solution 1
Change A so it has a default constructor.
class A
{
int x;
public:
A(int i = 0) { x = i; }
void print() { cout << x; }
};
Solution 2
Change D to:
class D: public B, public C {
public:
D() : A(0), B(), C() {}
};
or a simpler version,
class D: public B, public C {
public:
D() : A(0) {}
};
That's because D inherits from A indirectly using virtual. A doesn't have a parameterless constructor so a compiler-generated constructor for D can't be made.
Note: this is mostly just adding a reference to the standard, in case anybody might care (but as usual for him, #R. Sahu's answer is quite accurate).
The standard specifies ([class.base.init]/13) that:
In a non-delegating constructor, initialization proceeds in the
following order:(13.1) — First, and only for the constructor of the
most derived class (6.6.2), virtual base classes are initialized in
the order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is the
order of appearance of the base classes in the derived class
base-specifier-list.(13.2) — Then, direct base classes are
initialized in declaration order as they appear in the
base-specifier-list (regardless of the order of the mem-initializers).
So, since A is a virtual base class, it's initialized directly by the most derived class (D). Only afterward, the direct base classes are initialized--but for anything to compile, the most derived class must be able to initialize the virtual base class(es).
There is one point some might find interesting in a case like this. Let's modify your class structure just a tiny bit, so we to the necessary initialization, and (importantly) initialize with a unique value in each constructor:
#include <iostream>
class A {
int i;
public:
A(int i) : i(i) {}
void show() { std::cout << "value: " << i << "\n"; }
};
class B : virtual public A{
public:
B() : A(10) {}
};
class C : virtual public A {
public:
C() : A(20) {}
};
class D : public B, public C {
public:
D() : A(0) {}
};
int main() {
D d;
d.show();
}
In this case, what exactly happens? We have three different constructors each "thinking" it's going to initialize the A object with a different value? Which one "wins"?
The answer is that the one in the most-derived constructor (D::D) is the one that' used to initialize the virtual base class object, so that's the one that "wins". When we run the code above, it should print 0.

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.

output of multilevel inheritance program code

#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 : 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 obj=new C(2);
return 0;
}
when i am running this code it shows
In constructor 'C::C()':
88c8237e3ffce7819f082b210069fd59.cpp:19:13: error: no matching function for call to 'B::B()'
why this happens as i am only caling parameterized constructors explicitly everywhere.??please help
C() {cout<<"in C def cstr\n";}
You cannot declare
C() {cout<<"in C def cstr\n";}
Because neither of the base classes A nor B have default (non-parameterized) constructors. If you uncommented those out your code would compile (except for the comment below).
Side comment, this is not correct
C obj=new C(2);
You could use any of the following
C obj(2);
C obj{2};
C obj = C(2);
But with new you'd have to assign to a pointer (which I wouldn't recommend unless you need heap allocated objects for some reason, in which case prefer smart pointers).
C* obj = new C(2);
delete obj; // remember to delete it when you're done

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().