Объясните порядок вызовов конструктора / деструктора в этом коде 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()
Другие вопросы по тегам