Конструктор С++ и порядок деструктора

Я пытаюсь создать код о базовом классе и создании и уничтожении членов, и я запутался в некотором порядке constuctor и destructor, вывод этого кода:

Base1 constructor
Member1 constructor
Member2 constructor
Derived1 constructor
Member3 constructor
Member4 constructor
Derived2 constructor
Derived2 destructor
Member4 destructor
Member3 destructor
Derived1 destructor
Member2 destructor
Member1 destructor
Base1 destructor

Смотрите первые четыре строки, но я упал, порядок должен быть

Base1 constructor
Derived1 constructor
Member1 constructor
Member2 constructor

Кто-нибудь может мне объяснить?

#include "stdafx.h"
#include <fstream>
using namespace std;
ofstream out("order.out");

#define CLASS(ID) class ID { \
public: \
  ID(int) { out << #ID " constructor\n"; } \
  ~ID() { out << #ID " destructor\n"; } \
};

CLASS(Base1);
CLASS(Member1);
CLASS(Member2);
CLASS(Member3);
CLASS(Member4);

class Derived1 : public Base1 {
  Member1 m1;
  Member2 m2;
public:
  Derived1(int) : m2(1), m1(2), Base1(3) {
    out << "Derived1 constructor\n";
  }
  ~Derived1() {
    out << "Derived1 destructor\n";
  }
};

class Derived2 : public Derived1 {
  Member3 m3;
  Member4 m4;
public:
  Derived2() : m3(1), Derived1(2), m4(3) {
    out << "Derived2 constructor\n";
  }
  ~Derived2() {
    out << "Derived2 destructor\n";
  }
};

int main() {
  Derived2 d2;
} ///:~

Ответ 1

Конструкторы называются вверх в иерархии:

- base class member objects
- base class constructor body
- derived class member objects
- derived class constructor body

Выход правильный.

Позвольте упростить код:

struct BaseMember
{
   BaseMember() { cout << "base member" <<endl; }
};
struct Base
{
   BaseMember b;
   Base() { cout << "base" << endl; }
};
struct DerivedMember
{
   DerivedMember() { cout << "derived member" << endl; }
};
struct Derived : public Base
{
   DerivedMember d;
   Derived() { cout << "derived" << endl; }
};

Derived d;

Когда создается d, сначала создается часть Base. Прежде чем он войдет в тело конструктора, все объекты-члены инициализируются. Итак, BaseMember - это первый объект, инициализированный.

Затем вводится конструктор Base.

Прежде чем встраивается конструктор Derived, объекты-члены Derived инициализируются, поэтому DerivedMember создается, вызывается конструктор Derived.

Это происходит потому, что, когда вы вводите тело конструктора производного класса, базовые классы и объекты-члены должны быть полностью инициализированы.

EDIT Как отметил Маттиу, порядок, в котором инициализируются объекты-члены, определяется порядком, в котором они отображаются в определении класса, а не порядком, в котором они отображаются в списке инициализаторов.

Ответ 2

Конструктор класса выполняется позже, чем конструкторы его полей. Конструктор базового класса и всех его элементов выполняется раньше, чем конструктор производного класса и его членов.

Ответ 3

Ну, инициализация, выполняемая в списке инициализации, происходит перед телом конструктора Derived1, поэтому сначала вы видите вывод для m1 и m2.

В качестве более полного ответа возникает следующее: строятся первые базовые под-объекты, затем элементы строятся в порядке их объявления в классе (не их порядок в списке инициализации), затем выполняется тело конструктора, Разрушение происходит в обратном порядке.

В этом случае, когда вы строите Derived2, сначала он пытается построить под-объект Derived1. Это, в свою очередь, включает в себя сначала создание базового под-объекта, поэтому он делает это в первую очередь. Затем он создает элементы Derived1, выполняет тело конструктора Derived1, строит элементы Derived2 и, наконец, выполняет тело конструктора Derived2. Следовательно, наблюдаемый выход.

Ответ 4

Это просто потому, что m1 и m2 инициализируются в списке инициализации конструктора Derived1. Все в списке инициализации создается до ввода тела конструктора.

Ответ 5

Рассмотрим следующую программу, которая сделает вашу идею понятной!

#include<iostream.h>
class A
{
public:
  A()
    {
    cout<<"\nI am the base class constructor!";
    }
  ~A()
    {
    cout<<"\nI am the base class destructor!";
    }
};

class B : public A
{
public:
  B()
    {
    cout<<"\nI am the derived class constructor!";
    }
  ~B()
    {
    cout<<"\nI am the derived class destructor!";
    }
};

int main()
  {
  B obj;
  return 0;
  }

Вывод вышеуказанной программы будет следующим.

Я - конструктор базового класса!

Я - конструктор производного класса!

Я деструктор производного класса!

Я деструктор базового класса!

Я думаю, это объясняет и уточняет ваш запрос о порядке вызова конструкторов и деструкторов.