In virtual inheritance, the virtual base class is initialized by the final derived class, in other words, the constructor of the final derived class must call the constructor of the virtual base class. For the final derived class, the virtual base class is the indirect base class, not the direct base class. Unlike normal inheritance, in normal inheritance, a derived class constructor can call only the constructor of a direct base class and cannot invoke an indirect base class.
Here we demonstrate the invocation of the constructor with the example of diamond inheritance:
#include <iostream> using namespace std; Virtual base class A class a{public:a (int A); protected:int m_a;}; A::A (int a): M_a (a) {}//Direct derived class B class B:virtual public a{public:b (int a, int B) public:void display () protected:int M_b; }; B::B (int A, int B): A (a), M_b (b) {} void B::d isplay () {cout<< "m_a=" <<m_a<< "m_b=" <<m_b<< Endl }//Direct derived class C class C:virtual public a{public:c (int A, int C); public:void display (); Protected:int M_c;}; C::C (int A, int C): A (a), M_c (c) {} void C::d isplay () {cout<< "m_a=" <<m_a<< ", m_c=" <<m_c<< Endl }//Indirect derived class D class D:public B, public c{public:d (int A, int B, int C, int D); public:void display (); Private:int m_d;} ; D::D (int A, int b, int c, int D): A (a), B (b), C (c), M_d (d) {} void D::d isplay () {cout<< "m_a=" <<m_a< ;< ", m_b=" <<m_b<< ", m_c=" <<m_c<< ", m_d=" <<m_d<<endl; int main () {b b (a); B.display (); C C (30, 40); C.display ();D d (50, 60, 70, 80); D.display (); return 0; Run Results:
m_a=10, m_b=20
M_a=30, m_c=40
M_a=50, m_b=60, m_c=70, m_d=80
Note that the 50th line of code, in the constructor of the final derived class D, calls the constructor of a, in addition to the constructors for B and C, which means that D is responsible for initializing both the direct base class B and C and the initialization of the indirect base class A. In normal inheritance, the constructor of the derived class is only responsible for initializing its direct base class, and then initializing the indirect base class by the constructor of the direct base class, and the user attempting to invoke the constructor of the indirect base class will cause an error.
Virtual inheritance is now used, and virtual base class A retains only one member variable m_a in the final derived class D. If M_a is initialized by B and C, then B and C are likely to give different arguments when invoking the constructor of a, at which point the compiler is confused and does not know which argument to use to initialize the m_a.
To avoid this paradox, C + + simply stipulates that the virtual base class A must be initialized by the final derived class D, and that direct derived classes B and C are not valid for the invocation of A's constructor. In the 50th line of code, when invoking the constructor of B to attempt to initialize M_a to 90, the C constructor was invoked to attempt to initialize m_a to 100, but the output proved that these were invalid and M_a was eventually initialized to 50, which is exactly what the constructor of a is called in D. Results.
Another concern is the order in which constructors should be executed. The execution order of the constructors differs from the normal inheritance when the virtual inheritance occurs: In the constructor invocation list of the resulting derived class, the compiler always calls the constructor of the virtual base class, regardless of the order in which the individual constructors appear, and then calls the other constructors in the order in which they appear; is called in the order in which the constructors appear.
Modify the 50th line of code in this example to change the order in which the constructors appear:
D::D (int A, int b, int c, int D): b (M, b), C (c), a (a), M_d (d) {}
Although we put a () at the end, the compiler will still call a () and then call B (), C (), because a () is the constructor of the virtual base class, which is higher precedence than the other constructors.
In general, constructors are called in the order in which they are inherited. (Independent of argument list when initializing constructor)