This question already has an answer here:
The following code:
#include<iostream>
using namespace std;
class Man
{
int stories;
public:
Man(int stories) : stories(stories) {cout << "A man is created with " << stories << " stories." << endl;};
};
class Grandpa : public virtual Man
{
int pipes;
public:
Grandpa(int stories, int pipes) : Man(1000), pipes(pipes)
{
stories += stories;
cout << "Grandpa is created with " << stories << " stories and pipes." << endl;
};
};
class Father : public Grandpa
{
int cars;
public:
Father(int stories, int cars) : Man(1000), Grandpa(1000, 1), cars(cars)
{
stories += stories;
cout << "Father is created with " << stories << " stories and cars." << endl;
};
};
class Son : public Father
{
int girls;
public:
Son(int stories, int girls) : Man(1000), Father(1000, 3), girls(girls)
{
stories += stories;
cout << "Son is created with " << stories << " stories and girls." << endl;
};
};
int main()
{
Son Dick(1000, 5);
return 0;
}
Gives the following output on the run:
A man is created with 1000 stories.
Grandpa is created with 2000 stories and pipes.
Father is created with 2000 stories and cars.
Son is created with 2000 stories and girls.
And it does not compile, when I do not call Man(int) in Father's and Son's initializers' lists. It is trying to call Man(void), and Man() is not defined. Why is it so? Yet, I think, when Father's or Son's constructors were called, the virtual base's constructor had already been called in Grandpa! Moreover thus, I would expect the output to be:
A man is created with 1000 stories.
Grandpa is created with 2000 stories and pipes.
Father is created with 3000 stories and cars.
Son is created with 4000 stories and girls.
To recapitulate then: why a virtual base class constructor has to be called explicitly in an initializer list of a derived class, although it is already placed in an younger's ancestor initializer list? Why it is seemingly not called in the younger ancestor, and a default base class is tried to be called instead?
EDIT due to finding an answer to problem with numbers
What a shame :) I should have made int stories
in Grandpa protected int _stories;
and then the output would be as expected: 1000 stories for Man, 2000 for Grandpa, 3000 for Father and 4000 for Dick :) Otherwise stories += stories
acts on local variable instead of the Man's member... Sorry for bothering!
The call to the virtual base's constructor comes from the most-derived type of the object being created. In this case, that's
Son
, soSon
needs to callMan
's constructor.However, it's also possible to create a
Father
that isn't actually aSon
(e.g.,main
havingFather Dick(1000, 5)
). Because of that,Father
might end up being the one to initializeMan
, meaning it needs to callMan
's constructor. The same is true forGrandpa
.If you make
Man
,Grandpa
, andFather
abstract classes, they can no longer possibly be the ones to initializeMan
, and thus do not need a call to its constructor. However, GCC 6.1 gives me an error when I do this (Clang compiles it). I believe GCC to be wrong here.