When should constructor of virtual base class be called?

138 Views Asked by At

Consider the following example:

struct Grandpa {
    Grandpa(int x) {}
};

struct Dad : Grandpa {
    Dad(int y) : Grandpa(15) {}
};

struct Son : Dad {
    Son(int z) : Dad(z) {}
};

int main () {
    Son s(10);
}

It compiles just fine, however, if I make Grandpa not just baseclass of Dad, but virtual baseclass:

struct Grandpa {
    Grandpa(int x) {}
};

struct Dad : virtual Grandpa {
    Dad(int y) : Grandpa(15) {}
};

struct Son : Dad {
    Son(int z) : Dad(z) {}
};

int main () {
    Son s(10);
}

This code doesn't compile! Compilation fails with

example.cpp: In constructor ‘Son::Son(int)’:
example.cpp:12:27: error: no matching function for call to ‘Grandpa::Grandpa()’
   12 |         Son(int z) : Dad(z) {}

What are the rules, according to C++ standard, regarding virtual baseclasses' constructor calls?

2

There are 2 best solutions below

8
blonded04 On BEST ANSWER

As Pete Becker in comments, and Chris Dodd in answers have pointed out:

The constructor of a virtual base class is called from the constructor of the most derived class, in this case, from the constructor of Son. Since there is no default constructor for Grandpa, the constructor for Son needs to explicitly call the Grandpa constructor.

The closest thing that corresponds to this answer in C++ standard I found is: 15.6.2 Initializing bases and members # 13.1

What it says, is that order of which constructor is called is first virtual baseclasses (even non-direct baseclasses!!), and then direct non-virtual baseclassses. So compiler, after not seeing call to Grandpa constructor in Son constructor, doesn't bother calling Dad constructor to find call to Grandpa constructor there: compiler decides to fail compilation, which is OK for compiler, according to standard.

0
Chris Dodd On

Whenever you create an instance of a class with a (direct or indirect) virtual base class, that top level constructor must call the constructor for the virtual base class. Any constructor calls to the virtual base in intermediate classes will be ignored.

In your case, you are creating a Son and its constructor has no explicit call to Grandpa, so it gets an implicit call to Grandpa() (which causes the error you see). The presence or absence of any call in Dad's constructor is irrelevant; it will always be ignored.