3

As far as i know, virtual ensures that only one copy of the properties of base class is inherited to the derived class. And in a multiple inheritance the constructor of all base is called first then the constructor of derived is called. In the following code why was the constructor of class B called twice in a row? To my understanding the output should have been

B
B1
B2
D

but the output came out to be

B
B
B1
B2
D

Here's the full code.

#include <iostream>

class B
{
public:
    B(){std::cout << "B" << std::endl;}
};

class B1:public B
{
public:
    B1(){std::cout << "B1" << std::endl;}
};

class B2:virtual public B
{
public:
    B2(){std::cout << "B2" << std::endl;}
};

class D:public B1, public B2
{
public:
    D(){std::cout << "D" << std::endl;}
};

int main()
{
    D d1;
}

3 Answers3

5

The inheritance of B by B1 must be virtual too.

Virtual inheritance doesn't mean "look in the rest of the hierarchy for an instance of inheritance of this class", it means "use only one instance of inheritance for all virtual inheritances in this hierarchy".

Julien BERNARD
  • 653
  • 6
  • 17
  • okay i now understand that both B1 and B2 still has their own B. But why is the constructor order B->B->B1->B2->D ? Shouldn't it be B->B1->B->B2->D ? When B is not virtual for both B1 and B2, the order is B->B1->B->B2->D. How does making B virtual for B2 change the order of constructor? – Bijan Regmi Sep 13 '21 at 12:43
  • It seems to do (B for D's virtual classes) (B and B1 for B1) (B2 for B2) (D for D). Here the virtual goes first, but I don't know if the specs says anything about whether the constructions of the virtual classes must always go before any other parent class construction - it will go before the construction of any class it is parent from, though ! – Julien BERNARD Sep 13 '21 at 12:55
  • After doing some research, according to cppreference: "All virtual base subobjects are initialized before any non-virtual base subobject" https://en.cppreference.com/w/cpp/language/derived_class – Julien BERNARD Sep 13 '21 at 13:01
  • Thanks! I added more inheritance layers and found out that all virtual classes are initialized first. – Bijan Regmi Sep 13 '21 at 13:11
1

This is the classic "diamond problem" (described here). Your understanding of the virtual keyword is correct, but it only applies if you use it for both B1 and B2.

JimPri
  • 1,278
  • 8
  • 17
  • The memory layout was really handy to figure out things. I now understand the behavior of the order of constructor calls. – Bijan Regmi Sep 13 '21 at 13:12
-1

Write your code like this:

#include <iostream>

class B
{
public:
    B(){std::cout << "B" << std::endl;}
};

class B1:public B
{
public:
    B1(){std::cout << "B1" << std::endl;}
};

class B2:public B1
{
public:
    B2(){std::cout << "B2" << std::endl;}
};

class D:public B2
{
public:
    D(){std::cout << "D" << std::endl;}
};

int main()
{
    D d1;
}
Andronicus
  • 25,419
  • 17
  • 47
  • 88