Inheritance hierarchy: Constructor & Destructor execution sequence - c++

Here http://www.parashift.com/c++-faq-lite/multiple-inheritance.html section [25.14] says
The very first constructors to be executed are the virtual base classes anywhere in the hierarchy.
I tried to verify it using following program:
A (pure virtual)
|
B
|
C
(virtual)/ \ (virtual)
E D
\ /
F
|
G (pure virtual)
|
H
each class has a c'tor and virtual d'tor. the output is as follows:
A
B
C
E
D
F
G
H
~H
~G
~F
~D
~E
~C
~B
~A
Press any key to continue . . .
but as per quote virtual base classes constructors should be executed first.
what did I understand wrong?
EDIT: To clear my question, As per my understanding this behaviour has nothing to do with whether a base class is virtual or not. but quote insists on Virtual Base class. am I clear or something fishy there?

Virtual base classes cannot be constructed if the classes they inherit from are not constructed first. So in your case, non-virtual base classes are constructed because the virtual ones depend on them: C can't be constructed until A and Bare. Therefore, A and B are indeed constructed before C, even though C is virtually inherited.

Related

Diamond inheritance with additional class copy constructor

So I was wondering lately what the copy constructor of an class will look if we have a base class A that is being virtually inherited by B and C, where B and C are inherited by D and D is inherited by E.
So I am a bit confused. Should D's copy constructor still have the base class's (A) constructor in its initializing list or is that the job of E now? Am I correct that E could inherit D non-virtually?
The implicitly generated copy constructor works fine, but if you wanted to explicitly write it yourself it could look like:
D(D const &o): A(o), B(o), C(o) {}
E(E const &o): A(o), D(o) {}
For initialization purposes, virtual base classes behave as if they are a direct base of the most-derived object. Any initializer in a subobject is ignored (e.g. in my code for E, the initialization D(o) actually does not initialize the A despite the fact that A is listed in D's copy constructor).
This is the same whether or not E inherits D virtually.
Link to further reading
Yes, A should still be in the initializing list and E does not need to inherit D virtually. The order of construction should be:
A() --> B() --> C() --> D()

ladder-like C++ virtual inheritance

If I have a class inheritance relation like the following
a
/ \
b c
\ |
| d
\/ \
e f
\ /
g
Is the following the correct definition?
class A {};
class B: public virtual A {};
class C: public virtual A {};
class D: public C {};
class E: public B, public virtual D {};
class F: public virtual D {};
class G: public E, public F {};
I made both A and D virtually inherited because I assume each joint class need to be virtual.
Also I am not sure how C++ defines the constructor order of the above case. The link
https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order says
The very first constructors to be executed are the virtual base
classes anywhere in the hierarchy. They are executed in the order they
appear in a depth-first left-to-right traversal of the graph of base
classes, where left to right refer to the order of appearance of base
class names.
After all virtual base class constructors are finished, the
construction order is generally from base class to derived class. The
details are easiest to understand if you imagine that the very first
thing the compiler does in the derived class’s ctor is to make a
hidden call to the ctors of its non-virtual base classes (hint: that’s
the way many compilers actually do it). So if class D inherits
multiply from B1 and B2, the constructor for B1 executes first, then
the constructor for B2, then the constructor for D. This rule is
applied recursively; for example, if B1 inherits from B1a and B1b, and
B2 inherits from B2a and B2b, then the final order is B1a, B1b, B1,
B2a, B2b, B2, D.
Note that the order B1 and then B2 (or B1a then B1b) is determined by
the order that the base classes appear in the declaration of the
class, not in the order that the initializer appears in the derived
class’s initialization list.
If so, is the order like?
A, D, B, C, D, F, G
I do not expect D is constructed before C. What is the correct constructor order?
When constructing an object of class G, the virtual base classes are initialized first. This results in the constructors for A and D being called. The constructor for D will construct it's base C object. Then the constructors for the non-base classes of G will be called, which would be E and F. The constructor for E will call the constructor for B. This gives the final order:
A C D B E F G
I added constructors that call printf to watch what happens (code available on Godbolt for the curious). The order I got, with both clang (version 6.0.0) and gcc (versions 6.4.0 and 7.3.0), is:
A
C
D
B
E
F
G
This matches what I'd expect. A and D have to be constructed first, but you can't construct a D without a C (imagine a more complex example where D's constructor called into C. Once all virtual inheritance has been satisfied, the constructors are called in the same order we expect.

Virtual base class destructor calling ordering?

C++ FAQs item 20.05:
"Virtual base classes are special, their destructors are called at the
end of the most derived class' destructor (only)."
I dont really understand how this fits in with the typical:
"data member destructors first, then base class destructors" rule
How are virtual base classes special? I cannot tell what the above means :s
The key property of virtual base classes is that they always produce a single unique base subobject in any object of derived class. That's exactly what's special about virtual base classes and that makes them different from regular base classes, which can produce multiple subobjects.
For example, in this hierarchy
struct B {};
struct M1 : B {};
struct M2 : B {};
struct D : M1, M2 {}
there's no virtual inheritance. All bases are inherited using regular inheritance. In this case class D will contain two independent subobjects of type B: one brought in by M1, another - by M2.
+-> D <-+
| |
M1 M2
^ ^
| |
B B <- there are two different `B`s in `D`
The task of properly destructing all subobjects when destructing D is trivial: each class in the hierarchy is responsible of destructing its direct bases and only its direct bases. That simply means that destructor of M1 calls the destructor of its own B subobject, destructor of M2 calls the destructor of its own B subobject, while destructor of D calls the destructors of its M1 and M2 subobjects.
Everything works out nicely in the above destruction schedule. All subobjects get destructed, including both subobjects of type B.
However, once we switch to virtual inheritance things become more complicated
struct B {};
struct M1 : virtual B {};
struct M2 : virtual B {};
struct D : M1, M2 {}
Now there only one subobject of type B in D. Both M1 and M2 see and share the same subobject of type B as their base.
+-> D <-+
| |
M1 M2
^ ^
| |
+-- B --+ <- there is only one `B` in `D`
If we make a naive attempt to apply the previous destruction schedule to this hierarchy, we'll end up with the B subobject getting destructed twice: M1 calls the destructor of B subobject, and M2 calls the destructor of the very same B subobject.
That is, of course, completely unacceptable. Each subobject has to be destructed once and only once.
In order to solve this problem, when M1 and M2 are used as base subobjects of D, these are explicitly prohibited to call the destructor of their B subobject. The responsibility of calling the destructor of B is assigned to D's destructor. Class D, when used as a complete independent object (i.e. serves as a most derived class), knows that there's only one B in it and knows that the destructor of B has to be called only once. So, the destructor of class D will call the destructor of B for that unique base subobject of type B. Meanwhile, destructors of M1 and M2 will not even attempt to call the destructor of B.
That's how it works with virtual inheritance. And that what the rule you quoted says basically. The parts that says that virtual bases' destructors are called last simply means that each class'e destructor calls destructors for its direct regular base classes, and only after that, if necessary, it calls destructors of its virtual base classes (possibly indirect). In the above example, the destructor of D calls destructors of M1 and M2 and only after that it calls the destructor of B.
The entire paragraph of the book you are quoting was describing the order of destructors. Normally, in the class declaration, the order of the classes listed for inheritance determines the order of their construction, and then they are destructed in reverse order.
A virtual base class means virtual inheritance was used on it:
struct Base {};
struct D : virtual Base {};
struct D1 : D, virtual Base {};
struct D2 : virtual Base, D {};
ASCII art alert:
Base Base
| \ | \
/_\ \ | /_\
| \ | \
D /_\ | D
| / | /
/_\ / /_\ /_\
| / | /
D1 D2
The multiple inheritance collapses the diamond into a single line, in this case. But, the point is still illustrated. The order of inheritance for D1 and D2 doesn't matter. The order in which the destructors for D and Base are called will be the same for both of them.

Destructor ordering in inheritance hierarchy

If I have the following hierarchy:
Class F contains member objects of type (Class E and Class D, declared in that order)
Class F inherits the concrete class Class C
Class C inherits the abstract/pure virtual class Class B
Class B inherits the concrete class class A
If the destructor for object of type Class F is called, the following happen in the below order:
Class F (the most derived) destructor is called and finishes
Class D (member object 2) destructor is called and finishes
Class E (member object 1) destructor is called and finishes
Class C (base of F) destructor is called and finishes
Class A (base of B, which is base of C) destructor is called and finishes
Class B (virtual, base of C) destructor is called and finishes
is this correct? So basically towards the end C inherits virtual B and virtual B inherits A, but C gets destroyed, then A, then virtual B?
EDIT: C++ FAQs says:
"Virtual base classes are special- their destructors are called at the
end of the most derived class's constructor"
which is what I am trying to understand?
Destructors execute in reverse order of constructors. That is pretty much all you need to know.
UPDATE: It holds even for virtual bases. You just have to realize that virtual bases are constructed before any other base class.
Maybe it's easiest to express the order of destructor calls as an algorithm.
Destroy
Do whatever the programmer wrote in the destructor's body: F::~F() { do_this; do_that; }
Destroy (call destructors for) members
Destroy (call destructors for) non-virtual base classes
Destroy (call destructors for) virtual base classes
This algorithm is performed by the language (or compiler), so the programmer can control only the first step.
Note: each of the further steps is recursive.
The order of destructor calls is the reverse order of constructor calls (it's good to know because the construction order is intuitive). The order of destruction of virtual bases is specified as
depth-first left-to-right traversal of the graph of base classes
Fortunately, you don't need this because you only have one.

C++, diamond inheritance, where/when do pure virtuals need to be implemented?

C++: I have a base class A with a pure virtual function f() and then two classes B and C inherit virtually from A, and a class D that inherits from both B and C (the typical diamond structure):
A f() = 0
v/ \v
B C
\ /
D
Where and when does f() = 0 need to be implemented in the following cases?
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Neither B nor C have pure virtuals of their own (-> possible way to skip implementation in B and C and "pass it through" to D?)
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implement f()? In which cases, if any, is it not possible for D to implement f()?
Are there any other common suggestions for these kind of problems?
Thanks.
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Yes D MUST implement ALL the inherited pure virtual functions.
Unless a class implements all the pure virtual functions of the classes it derives from the class itself actas as an Abstract class.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
D will have to implement the pure virtual function it inherits through its Base classes in any hierarchy. If its immediate Base class does not define a Pure virtual function, then that class becomes an Abstract class too, and unless D implements the inherited pure virtual function, it will become Abstract too.
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
D will have to implement the the pure virtual functions it inherits through A->B & A-C.Note that in this case both B and C will be Abstract classes.
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implement f()?
D needs to implement foo() in all the above 3 conditions, to be able to be instantiable(Non-Abstract).
Conclusion:
A class needs to implement ALL the pure virtual functions it inherits from ALL it's base classes, failing to do so will make the class an Abstract class.
Virtual attribute is inherited, If a Super class declares a function virtual then the overridden function in the derived class is virtual too and it passes down the virtual attribute to all classes deriving from it.
Avoid the Diamond of Death! Unless you really understand the subtleties involved with it. A lot of people try to use virtual Inheritance when it is not really the most apt way to achieve what their design wants to achieve. The use of Virtual Inheritance is indeed necessary in some scenarios, it is nevertheless an important construct provided by the language, but more often used in wrong ways. So it makes sense to revisit your design once to verify if you really need virtual Inheritance.
Following might be a good read:
Multiple Inheritance - Part I
Multiple Inheritance - Part II
Multiple Inheritance - Part III
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?
Yes. Any class that is inherited from abstract class must implement virtual functions to be able to instantiate. Or else they will also be abstract.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Since C also derived from A, it should also implement f().
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
You can do that. But that prevents instantiation of B or C alone like -
A *obj = new B(); // Error
A *obj = new C(); // Error
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implment f()?
f() can be implemented in D alone as long as you do want all of it's parent classes to be abstract.
The only requirement is that at the "leaf" level (the most derived one) everything has an implementation (and possibly one only, otherwise ambiguity can arise if -at the point you access the graph- there are more implementation at a same "distance".
So D must implement everything has not been implemented yet, or everything has been implemented more than once through different paths (to disambiguate).
If something -at D level- is still left unimplemented ... D cannot be instatiated, and the implementation is demanded to and E, derived from D.
- Diamonds are forever -
No, abstract classes (presumably B and C) don't need to implement inherited pure virtuals. A child class like D will need to do so to be instantiated though.
No, again B and C will inherit the pure virtual method and it need only be overridden to generate a final concrete class.
Yes, this would pass through implementation to D, in one of two ways. If B and C both inherit virtually, then D would implement it once. If they don't inherit virtually then D would need to override both the B and C versions of f to be concrete.
If D is abstract it never needs to implement f. Assuming you mean it to be concrete, in all three cases you'd need to override f in D. Only if both B and C override f would D not need to.
Take a long look at your design and remove the diamond inheritance. In most cases that's going to be your best bet to prevent all these sorts of issues.