Объясните порядок вызовов конструктора / деструктора в этом коде C++
У меня есть этот код C++:
class BaseClass {
int id;
public:
BaseClass() { printf("BaseClass()\n"); }
virtual ~BaseClass() { printf("~BaseClass()\n"); }
};
class Class1 : public BaseClass
{
int id;
public:
Class1() { printf("Class1()\n"); }
~Class1() { printf("~Class1()\n"); }
};
class Class2 : public Class1
{
BaseClass id;
public:
Class2() { printf("Class2()\n"); }
~Class2() { printf("~Class2()\n"); }
};
class Class3 : virtual public BaseClass
{
int id;
public:
Class3() { printf("Class3()\n"); }
~Class3() { printf("~Class3()\n"); }
};
class Class4 : public Class3, virtual public Class1
{
Class3 id;
public:
Class4() { printf("Class4()\n"); }
~Class4() { printf("~Class4()\n"); }
};
int main(int argc, char* argv[])
{
BaseClass *p = new Class2;
Class2 *p1 = new Class2;
Class3 *p2 = new Class3;
delete p;
delete p1;
delete p2;
return 0;
}
Это вывод:
BaseClass()
Class1()
BaseClass()
Class2()
BaseClass()
Class1()
BaseClass()
Class2()
BaseClass()
Class3()
~Class2()
~BaseClass()
~Class1()
~BaseClass()
~Class2()
~BaseClass()
~Class1()
~BaseClass()
~Class3()
~BaseClass()
и я не понимаю почему. Я ожидаю, что результат будет следующим:
BaseClass()
Class1()
Class2()
BaseClass()
Class1()
Class2()
...
и т.п.
Почему нет Class2()
напечатано после Class1()
при создании, например, p1
? Это как-то связано с виртуальным наследованием?
2 ответа
Давайте шаг за шагом начнем с создания первого объекта:
new Class2;
Это первый объект, который вы строите, давайте назовем его p
,
BaseClass()
p
"s BaseClass
,
Class1()
p
"s Class1
подкласс BaseClass
строится.
BaseClass()
Это id
член Class2
строится.
Class2()
И вот, наконец, Class2
, p
сам.
Итак, несмотря на вашу веру в противном случае, Class2()
печатается после Class1()
, За исключением того, что вы забыли это Class2
также имеет id
член, это BaseClass
и который также должен быть построен до Class2::Class2()
конструктор вызывается. Вы верили, что видите второе new
Эд объект BaseClass
быть построенным, но то, что действительно строилось, было BaseClass
член объекта.
PS это C++
, В C++
мы используем std::cout
вместо printf
(). printf()
это так... в прошлом веке.
Почему Class2() не печатается после Class1() при создании, например, p1?
Так как Class2
имеет нестатический объект-член с типом BaseClass
его ctor будет вызываться перед ctor Class2
,
Согласно порядку инициализации:
Порядок инициализации
1) Если конструктор предназначен для самого производного класса, виртуальные базовые классы инициализируются в том порядке, в котором они отображаются в порядке обхода слева направо деклараций базового класса в глубину (слева направо относится к внешнему виду в списках базовых спецификаторов)
2) Затем прямые базовые классы инициализируются в порядке слева направо, как они появляются в списке базовых спецификаторов этого класса.
3) Затем не статические члены данных инициализируются в порядке объявления в определении класса.
4) Наконец, тело конструктора выполняется
За new Class2;
, прямой базовый класс Class1
и его базовый класс BaseClass
будет вызван в первую очередь. А потом нестатический член данных id
с типом BaseClass
будет вызван. И тело ctor of Class2
будет вызван в конце концов. Так вы получите
BaseClass()
Class1()
BaseClass()
Class2()