Virtual inheritance impact on constructor - c++

I've started learning about virtual inheritance (and how it may solve problems of having a class derived from two parent classes with same parent). To better understand the mechanism behind it, i made a following example:
class A {
public:
A(string text = "Constructor A") { cout << text << endl; }
};
class B: public A {
public:
B(): A("A called from B") { cout << "Constructor B" << endl; }
};
class C : virtual public A {
public:
C() : A("A called from C") { cout << "Constructor C" << endl; }
};
class D : public B, public C {
public:
D() { cout << "Constructor D" << endl; }
};
I have class A, class B derived from A, class C virtually derived from A, and class D derived from B and C. In main i just form an object of class D: D d; and i get the following output
Constructor A
A called from B
Constructor B
Constructor C
Constructor D
What bothers me is, why is there "Constructor A" signalizing that it is not called by either class B or C. And why is there not "A called from C" before "Constructor C". For the latter one i know it has to do with the class C being virtually derived so i guess it does not call Constructor A again since object from class A has already been formed (twice in fact).
EDIT:
In main i just make one object type D.
int main() {
D d;
}

Firstly, since B derives from A non-virtually, D ends up with two A subobjects (as if you didn't use virtual inheritance at all).
The non-virtual A is constructed by B() (hence "A called from B"), and the virtual one prints "Constructor A" when constructed.
That's because the constructors of virtual (possibly indirect) bases are always called by the constructor of the most derived class (D), rather than by the constructors of any intermediate bases (C).
It means that : A("A called from C") in C() is ignored (since you're not constructing a standalone C). And since D() doesn't mention A in its member initializer list, the virtual A is constructed without any parameters (as if by : A()).
Also, it's worth mentioning that all virtual bases are constructed before the non-virtual ones.
So your code is guaranteed to print Constructor A before A called from B.

The problem
Your code forgot something and you still have two A objects in a D object. You can verify this claim by adding a public int test member to A and try the following code. You will get two different addresses:
D d;
cout << &d.B::test <<endl; // the non virtual A subobject of B
cout << &d.C::test <<endl; // the virtual A subobject of C
Online demo
The solution
All classes that share A virtually and that directly inherit from A must declare the virtual inheritance. So you need to correct class B:
class B: virtual public A {...} // you forgot the virtual here
The code snippets above would work as expected, and you could even address d.test without getting any ambiguity error. Online demo
Edit: The delicate construction of A
The C++ rules require each object with a virtual A sub-object to provide a constructor for A. In your case, D should provide for the virual A's construction.
Since there is no explicit constructor, D will look for a default-construct A. And it finds one, since you provide a default argument for the A constructor. It's misleading because it tells you "A constructor" when in reality it was D that used it.
If you remove this default argument, your code won't compile anymore. You then need something like this to get A properly constructed:
class A {
public:
int test;
A(string text) { cout << "A is constructed: "<<text << endl; }
};
class D : public B, public C {
public:
D() : A("Mandatory, if there is no default consructor") { cout << "Constructor D" << endl; }
};
Online demo
Why are the C++ construction rules like that ? Because when you have virtual inheritance, there is no reason that the A construction by B is drawn over the construction by C . Nor the contrary. On the other side, both B and C define how to construct their A sub-object. To solve the ambiguity in the choice of the right construction, this rule was decided. And it may be painful if the virtual class doesn't have a default constructor.

When a type has a virtual base, the virtual base gets constructed from the constructor of the most-derived type. So "Constructor A" is called from D's constructor.
A bit more detail:
#include <iostream>
struct base {
base() { std::cout << "base()\n"; }
base(int) { std::cout << "base(int)\n"; }
};
struct i1 : virtual base {
i1() : base(0) { std::cout << "i1()\n"; }
};
struct i2 : virtual base {
i2() : base(1) { std::cout << "i2()\n"; }
};
struct d : i1, i2 {
};
Now, if the code creates an object of type i1 the default constructor for i1 calls base(int), as written.
But when you create an object of type d, the constructor for d is responsible for constructing the base object. Since d does not have a default constructor, the compiler generates one that calls the default constructor for base before it calls the default constructors for i1 and i2.
int main() {
d d_obj;
return 0;
}
the output here is
[temp]$ Clang++ test.cpp
[temp]$ ./a.out
base()
i1()
i2()
[temp]$
Note that the constructors for i1 and i2 did not construct the base subobject. The compiler took care fo that: the base should only be initialized once, and the constructor for d did that.
If you want a different initialization for the base object, write that in the constructor:
d::d() : base(2) {}
adding that to the class d produces this output:
[temp]$ Clang++ test.cpp
[temp]$ ./a.out
base(int)
i1()
i2()
[temp]$

Related

Constructors calling in c++ (inherited classes)

#include <iostream>
class A
{
public:
A() { std::cout << "A's constructor called\n"; }
};
class B
{
public:
B() { std::cout << "B's constructor called\n"; }
};
class C: public B, public A // Note the order
{
public:
C() { std::cout << "C's constructor called\n"; }
};
int main()
{
C c;
return 0;
}
Why is the constructor of class A and B called, when a new instance of C is created?
Output is
B's constructor called
A's constructor called
C's constructor called
C is derived from both A and B - so before the constructor for C can be executed, the constructors for A and B must both be completed. If that wasn't the case, then the C constructor could not rely on anything that its base classes provided.
For example, suppose A contained a list of items which is created and filed from a database in its constructor. All instances of A can rely on the list being complete because the constructor has to be finished before the instance is available to the rest of the code. But C is also an A - it derives from it in the same way that "a Ford" is also "A Car" - so it may well want to access that list. When you construct an instance, the base class constructors are automatically called before the derived classes to ensure that everything is ready for action when the derived constructor starts.
For example, change your code slightly:
class A
{
public:
A() { cout << "A's constructor called" << endl; }
};
class B: public A
{
public:
B() { cout << "B's constructor called" << endl; }
};
class C: public B
{
public:
C() { cout << "C's constructor called" << endl; }
};
int main()
{
C c;
return 0;
}
and you will get:
A's constructor called
B's constructor called
C's constructor called
Because the base class constructors are all completed before the derived ones are executed.
Why wouldn't it be? A C contains parts that are a B and an A respectively, and those parts need to be constructed as well. The constructor is the feature that performs this role.
kanishk tanwar's answer has more detail, but I was writing this anyway, so here's a very whistle stop tour of why it's happening to answer your question:
In order to ensure an instance of a class is properly initialised, a constructor for the base types are always called. If you don't specify which constructor you want to call (syntax: C() : B(), A() for C's constructor), the default constructor is used. As a derived class builds on a base class, the base classes have to be constructed first.
In your case you have specified contents to your default constructor, so that is the code that is run when you instantiate C.

Why default constructor of most base class (Virtual) is not getting called in private virtual inheritance while creating object of most derived class?

How default constructor of most base class is getting called in private virtual inheritance while creating object of most derived class. But the same does not get called when mentioned in constructor initializer list of most derived class.
#include<iostream>
using namespace std;
class A
{
public:
A() {cout << "1";}
};
class B: private virtual A
{
public:
B() {cout << "2";}
};
class C: private virtual A
{
public:
C() {cout << "3";}
};
class D: private B, private C
{
public:
D() : A(), B(), C() {cout << "4";}
//D() {cout << "4";}
};
int main()
{
D d1;
cout << "\n";
}
My Problem:
For Below mentioned code
D() : A(), B(), C() {cout << "4";}
I get below compilation error:
error: 'class A A::A' is inaccessible within this context
Why A() constructor is inaccessible here?
On the other hand below mentioned code gets compiled successfully and A() constructor gets called.
D() {cout << "4";}
Output of the program is:
1234
Means A() constructor is getting called.
So, Why is the change in behavior for calling of constructor A() in above two cases?
What I know:
(1) When I do 'Public Virtual inheritance' of B & C, then default constructor of most base class is gets called even if it's in mentioned in constructor initializer list of most derived class.
Means below statement compiles.
D() : A(), B(), C() {cout << "4";}
(2) In virtual Inheritance, constructor of virtual base class is called directly from most derived class's constructor.
It might be a concept issue for me of virtual inheritance. Kindly help me to understand this and share good references for that.
A is private from the point of view of D, but even if it wasn't it is incorrect for D to try to construct A. It should only construct direct base classes and instance member objects. B and C will both see to the construction of A by default.
As was mentioned in the comments, A() cannot be explicitly called from D() because A() is a private member of B and C. private inheritance gives access to public and protected members and makes them private. Whatever was private, is not inherited. So the key point is access specifiers during inheritance, not virtual inheritance. You can try and remove virtual from your example. The program will print 12134 because virtual inheritance was providing a common base object.
In case someone wonders why 1234 (or 12134 in non-virtual case) is outputted by the program, I invite them to read about the order of construction of derived classes:
https://www.learncpp.com/cpp-tutorial/order-of-construction-of-derived-classes/

How to call copy constructor of all base classes for copying most derived class object in diamond inheritance in C++?

Consider the below code:
#include<iostream>
using namespace std;
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C
{
public:
D() {cout << "7";}
D(const D & obj) {cout << "8";}
};
int main()
{
D d1;
cout << "\n";
D d(d1);
}
The output of the program is below:
1357
1358
So, for line D d(d1) the copy constructor of D class is bein called. During inheritance we need to explicitly call copy constructor of base class otherwise only default constructor of base class is called. I understood till here.
My Problem:
Now I want to call copy constructor of all base classes during D d(d1) execution. For that if I try below
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
Then I get this error:
error: 'class A A::A' is inaccessible within this context
How to resolve the issue. I want copy constructor of A, B and C when copy constructor of D gets called. It might be very small change but I am not getting.
First, lets change your inheritance as currently it is private:
class B : virtual protected A {...};
class C : virtual protected A {...};
Now, in your copy constructor, explicitly specify that the copy constructors of A and B and C should be called:
class D : protected B, protected C {
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
And the output will be as desired (2468).
Why?
When we have virtual base classes, they must be initialized by the most derived class, otherwise there would be ambiguity concerning whether B or C for example is responsible for the construction of A.
§12.6.2, (13.1):
In a non-delegating constructor, initialization proceeds in the following order:
First, and only for the constructor of the most derived class (1.8),
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.
In particular, if you define a copy constructor, and omit the list of copy constructors it should call, then the default constructors will be used.
The way you have inherited your classes, all of them use private inheritance.
By changing the inheritance of B from A and C from A to be protected or public, you can resolve the problem.
class B : protected virtual A
{
...
}
class C : protected virtual A
{
...
}
or
class B : public virtual A
{
...
}
class C : public virtual A
{
...
}
and then update D's copy constructor to:
D(const D & obj) : A(obj), B(obj), C(obj) {cout <<"8";}
PS It's baffling to me that the default constructor works even with private inheritance.
Alternative solution which doesn't require changing the inheritance modifiers of class B or C:
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C,virtual A
{
public:
D() {cout << "7";}
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
Regarding access checking for constructors: from [class.access]/6
All access controls in Clause [class.access] affect the ability to
access a class member name from the declaration of a particular entity
... [ Note : This access also applies to implicit references to
constructors, conversion functions, and destructors. — end note]
similarly, [class.access]/4
Special member functions obey the usual access rules. [ Example:
Declaring a constructor protected ensures that only derived classes
and friends can create objects using it. — end example ]
Regarding base class subobject initialization: from [class.base.init]/9
In a non-delegating constructor, if a given potentially constructed
subobject is not designated by a mem-initializer-id (including the
case where there is no mem-initializer-list because the constructor
has no ctor-initializer), then ... otherwise, the entity is
default-initialized
The lack of any ctor-initializer for a base class subobject means that the subobject is default-initialized; from [dcl.init]/7
To default-initialize an object of type T means: ...
The constructor thus selected is called, with an empty argument list,
to initialize the object.
So the lack of any base in a ctor-initializer is a request for default-initialization for that base, which means calling the default constructor.
The lack of mention of a base class makes no difference; in any case, a constructor has no name and is not named in the ctor-initializer, it is referenced either explicitly or implicitly. There is nothing in the standard suggesting that access control should not be performed in such case.
It seems like the constructor, being from an inaccessible base class, cannot be called either way, so your program should not compile.
In any case, you can change the inheritance from private to protected, even add a path to the virtual base class:
class D: B, C, virtual A
{
This way, the virtual base class A is still private, but is accessible to D.

virtual inheritance in c++ misunderstood

I read that in virtual inheritance, constructors are called "from the most derived".
consider the following code. In my opinion, the most derived class here is D. then B and C and the "most-not-derived" is A.
So how come the most "Base" constructor is called first and not the "most derived"?
Thanks.
#include <iostream>
using namespace std;
struct A
{
A()
{
cout << "A default constructor" << endl;
}
};
struct B : virtual public A
{
B() : A()
{
cout << "B default constructor" << endl;
}
};
struct C : virtual public A
{
C() : A()
{
cout << "C default constructor" << endl;
}
};
struct D : public B, public C
{
D() : B(), C()
{
cout << "D default constructor" << endl;
}
};
int main()
{
D d;
}
This is the output :
A default constructor
B default constructor
C default constructor
D default constructor
UPDATE:
Ok. so consider the following code.
Notice that 10 was printed although D,B and C constructors sent 7.
Here actually the base class IS the first one that is called.
There was no chain from D to B to A.
A() was called first (actually it's default constructor). and only then B and C constructors were called.
But I read : "from the most derived."
Source : c++ virtual inheritance
the most derived here is D then B and C and only then A. So how come that A is called first without even considering the parameters B,D,C transfer to it from their constructors ?
Thanks.
The code :
#include <iostream>
using namespace std;
struct A
{
int _x;
A()
{
_x = 10;
cout << "A default constructor" << endl;
}
A(int x)
{
_x = x;
cout << "A NOT-default constructor" << endl;
}
};
struct B : virtual public A
{
B(int x=7) : A(x)
{
cout << "B constructor" << endl;
}
};
struct C : virtual public A
{
C(int x=7) : A(x)
{
cout << "C constructor" << endl;
}
};
struct D : public B, public C
{
D(int x=7) : B(x), C(x)
{
cout << "D constructor" << endl;
}
};
int main()
{
D d;
cout << d._x;
}
The output :
A default constructor
B constructor
C constructor
D constructor
10
Construction order is quite simple in C++:
You call a most-derived ctor (By initializing a variable; auto-storage-class, static, dynamic, whatever).
That ctor initializes all sub-objects:
A delegating ctor calls another most-derived-ctor.
A non-delegating ctor does the work itself:
Iff the most-derived ctor, virtual bases in left-first declaration-order. (That means arguments to the virtual-base ctor given by non-most-derived-ctors are ignored)
The other direct bases in left-first declaration-order.
The members in declaration-order.
The ctors body runs.
As your most-base ctor is for the only virtual base, its body is the first ctor-body to run, called directly by the most-derived ctor.
In general, calling virtual functions, typeid and dynamic_cast is safe, though not before the base-subobjects are all initialized: May I call a virtual function to initialize a base-class sub-object?
That means that it's the responsibility of the most derived class to initialise any virtual base sub-objects, as well as those that it immediately derives from. That is, all the base constructors are called from the most-derived constructor: the constructor for D calls the constructor for A, then B and C, and finally initialises itself. This is necessary to ensure that the shared base object is initialised just once, and before any of the classes that derive from it.
It doesn't mean that the order is from the most to least derived. As with regular inheritance, base sub-objects are always initialised first, so they're available when initialising the derived classes.
To answer your updated question, since D initialises A, it will call the default constructor unless its initialiser list contains an entry for A:
D(int x=7) : B(x), C(x) // calls A(), initialising with 10
D(int x=7) : A(x), B(x), C(x) // calls A(int), initialising with 7
Any entry for A in the initialiser list of B (or C) is only used when B (or C) is the most derived class (and so is responsibly for initialising A).
How do you propose any derived class to behave if its constructor code ran before the base class was constructed? While technically possible, it'd be entirely useless.
The behavior you observe is the only sane one, and has nothing to do with virtual inheritance.
You said
I read that in virtual inheritance, constructors are called "from the most derived".
That is true. Let me elaborate.
In your case, D is the most derived.
When you construct an instance of D, the constructors for A is called from the constructor of D since there is only instance of A for each instance of D. Constructor for A will not be called from the constructor of B or C.
When you construct an instance of B, then constructor for A is called from the constructor of B. Similarly for an instance of C.
If you had a sub-type of D,
struct E : public D
{
};
and you create an instance of E, then the constructor of A will be called from the constructor of E.
The C++ Draft Standard (N3337) says this about initialization involving virtual base classes:
12.6.2 Initializing bases and members
5 Initialization shall proceed in the following order:
— First, and only for the constructor of the most derived class as described below, virtual base classes shall be 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 class names in the derived class base-specifier-list.
That is how objects are built.
UPDATE
Check this example out:
class A{
A()
{
cout << "Constructor A"<<endl;
}
~A()
{
cout << "Destructor A"<<endl;
}
}
class B : public A{
B()
{
cout << "Constructor B"<<endl;
}
~B()
{
cout << "Destructor B"<<endl;
}
}
class C : public B{
C()
{
cout << "Constructor C"<<endl;
}
~C()
{
cout << "Destructor C"<<endl;
}
}
Creating an object of class C:
C obj;
The output will be as follows:
Constructor A
Constructor B
Constructor C
Destructor C
Destructor B
Destructor A
The reason for the execution is this:
When a class derives from another class, it derives the properties of that class. Functionalities of the derived class may or may not depend on the functionalities of the base class, but it can never be the other way. Assuming the derived class depends on the base class functionalities, it is important that the base class is properly initialized before the derived class can be initialized.
UPDATE:
When an object of C is made, he control from C constructor is transferred to it's base class' constructor, before C's constructor can execute. That's what I meant by base class first.
UPDATE:
Your question can be best answered by drawing the object relationship.
We'll have A right on the top and D at the bottom.
"in virtual inheritance, [virtual base] constructors are called from the most derived" [type's constructor]. "
By the above statement, they're asking you to start from the most derived type's constructor (D) and transverse up to the most base class' (A) constructor.
UPDATE:
#leemes has made the execution flow clearer in the comments:
It is the constructor itself which "redirects" to the base's constructor. After this returns, it continues with its own constructor. What you miss is that what is written in curly braces is not the whole implementation. It's only what comes after the call to the base ctor and initializing the member variables. Same with ctor: You write in curly braces what is to be executed before calling the ctor of member variables and then the ctor of the base.

Constructors order

#include <iostream>
class A
{
public:
A() { std::cout << " A ctor" << std::endl; }
A(int i) { std::cout << " A ctor i" << std::endl; }
~A() { std::cout << " A dtor" << std::endl; }
};
class B: public A
{
public:
B() : A () { std::cout << " B ctor" << std::endl; }
~B() { std::cout << " B dtor" << std::endl; }
};
class C: public A
{
public:
B _b;
C() : _b (), A () { std::cout << " C ctor" << std::endl; }
~C() { std::cout << " C dtor" << std::endl; }
};
int main ()
{
C c;
}
The output is:
A ctor
A ctor
B ctor
C ctor
C dtor
B dtor
A dtor
A dtor
What is the order of the init. list? Why, in the init. list of C, ctor of A called before ctor of B? I thought the output should be:
A ctor
B ctor
A ctor
C ctor
C dtor
A dtor
B dtor
A dtor
Thanks.
The order in which you write initializations in the initialization list is not important, the order of initialization is determined independently of that list by other rules:
First the base class is initialized. That's why in the construction of C the base class constructor A is called first. Everything that belongs to the base class is constructed in this step (base classes and member variables belonging to the base class), just like when a normal object of that base class would be constructed.
Then the member variables of the derived class are initialized, in the order in which they are declared in the class. So if there are several member variables, the order in which they are declared determines the order in which they are initialized. The order of an initialization list is not important.
Base class constructors are called before derived class constructors. This allows the derived class to use members in the base class during their construction.
During destruction, the opposite is true. Subclass destruction occurs before the base class, for exactly the same reason.
If you think about it - it makes perfect sense. The base class has no knowledge of the subclass, but the opposite is not true. This determines the ordering in order for everything to work as expected.
I think your confusion is why is C's initialization list processed right to left instead of left to write. It is because, the compiler processes parameters in "last in first out" fashion. Hence the order: First A's c'tor. Since _b is an object of B which is derived from A, base class is constructed before the derived class so A c'tor is called and then B's c'tor. And finally, C's c'tor is called. When C's object is destructed, it follows the reverse order.
If you use GNU compiler, -Wall option will help you.