В каком порядке называются деструкторы и конструкторы в C ++ - PullRequest
46 голосов
/ 17 марта 2009

В каком порядке деструкторы и конструкторы вызываются в C ++? Используя примеры некоторых базовых классов и производных классов

Ответы [ 4 ]

58 голосов
/ 17 марта 2009

Порядок:

  1. Базовый конструктор
  2. Производный конструктор
  3. Производный деструктор
  4. Базовый деструктор

Пример:

class B
{
public:
  B()
  {  
    cout<<"Construct B"<<endl;
  }

  virtual ~B()
  {
    cout<<"Destruct B"<<endl;
  }
};

class D : public B
{
public:
  D()
  {  
    cout<<"Construct D"<<endl;
  }

  virtual ~D()
  {
    cout<<"Destruct D"<<endl;
  }
};



int main(int argc, char **argv)
{
  D d; 
  return 0;
}

Вывод примера:

Конструкция B

Конструкция D

Уничтожить Д

Уничтожить Б

Несколько уровней наследования работают как стек:

Если вы рассматриваете помещение элемента в стек как конструкцию, а удаление его как уничтожение, тогда вы можете рассматривать несколько уровней наследования как стек.

Это работает для любого количества уровней.

Пример D2 получен из D, получен из B.

Нажмите B на стеке, нажмите D на стеке, нажмите D2 на стеке. Таким образом, порядок строительства B, D, D2. Затем, чтобы узнать порядок уничтожения, начните появляться. D2, D, B

Более сложные примеры:

Для более сложных примеров, пожалуйста, смотрите ссылку, предоставленную @ JaredPar

21 голосов
/ 17 марта 2009

Подробное описание этих событий, включая виртуальное и множественное наследование, доступно на C ++ FAQ Lite. Разделы 25.14 и 25.15

https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

10 голосов
/ 17 марта 2009

Также имейте в виду, что хотя элементы массива создаются первым -> последним, они уничтожаются в обратном порядке: последний -> первый.

4 голосов
/ 07 марта 2017

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

Если у вас есть производный экземпляр класса, являющийся созданным , то верно, что код внутри конструктора base будет называться до кода внутри конструктора производного , но имейте в виду, что производное все еще технически "создано" до база .

И когда у вас вызывается деструктор производного класса, это правда, что код внутри производного деструктора до * 1038 называется код внутри деструктора базы, но также имейте в виду, что база уничтожена до * * получена одна тысяча сорок-девять .

Когда я говорю создано / уничтожено Я на самом деле имею в виду выделено / освобождено .

Если вы посмотрите на структуру памяти этих экземпляров, вы увидите, что производный экземпляр составляет базовый экземпляр. Например:

Память производных: от 0x00001110 до 0x00001120

Память базы: от 0x00001114 до 0x00001118

Следовательно, производному классу должна быть выделена ДО база в конструкции. И производный класс должен быть освобожден ПОСЛЕ базы в уничтожении.

Если у вас есть следующий код:

class Base 
{
public:
    Base()
    {
        std::cout << "\n  Base created";
    }
    virtual ~Base()
    {
        std::cout << "\n  Base destroyed";
    }
}

class Derived : public Base 
{
public:
    Derived()
    // Derived is allocated here 
    // then Base constructor is called to allocate base and prepare it
    {
        std::cout << "\n  Derived created";
    }
    ~Derived()
    {
        std::cout << "\n  Derived destroyed";
    }   
    // Base destructor is called here
    // then Derived is deallocated
}

Итак, если вы создали Derived d; и вывели его из области видимости, тогда вы получите вывод в ответе @ Brian. Но поведение объекта в памяти на самом деле не в том же порядке, оно выглядит примерно так:

Конструкция:

  1. Производное выделено

  2. База выделена

  3. Базовый конструктор называется

  4. Производный конструктор с именем

Уничтожение:

  1. Производный деструктор с именем

  2. Базовый деструктор называется

  3. База освобождена

  4. Производные освобождены

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...