Каков порядок инициализации у учеников?

Я только что прочитал в этот ответ что если у вас есть следующий код

class Base
{
public Base()
{

}
}

class One : Base
{
string test = "text";
}

class Two : Base
{
string test;
public Two()
{
test = "text";
}
}

Для класса One инициализация One.test будет инициализирована до вызова Base :: Base. Но Two.test будет инициализирован после вызова Base :: Base.

Я предполагаю, что это потому, что в обоих случаях это

  1. поля <- это включает в себя One.test
  2. Основание :: Base ()
  3. Один :: Один () или Два :: Два () <- который инициализирует Two.test

Я думаю, что я помню, что списки инициализации находятся прямо перед конструктором.
Так же как и порядок инициализации:

  1. поля
  2. базовый список инициализаторов
  3. базовый конструктор
  4. собственный список инициализаторов
  5. собственный конструктор

И где появляются поля Базы? Все поля инициализируются первыми, когда выделяется память, или непосредственно перед списком инициализации текущего базового класса?

И есть ли другие шаги в списке, которые вы можете придумать?

Буду признателен, если кто-нибудь сможет дать хороший обзор.

0

Решение

Инициализация C ++ происходит в следующем порядке:

  1. Базовые классы, слева направо
  2. Переменные-члены в том порядке, в котором они находятся объявленный

Инициализация базовых классов с шага 1 рекурсивно требует тех же шагов. Следовательно, все базы полностью построены до того, как произойдет инициализация любой переменной-члена, и до того, как тело конструктора начнет выполнение.

Поэтому, когда компилятор встречает:

Two two;

Первый, Two::Two начинает выполнение, начиная со списка инициализаторов. Все базы инициализируются через список инициализации, даже если вы не написали ни одну или не указали инициализацию базового класса. Итак, код, который на самом деле выполняется, выглядит примерно так:

Two::Two
:
One(),
test()
{
test = "text";
}

Список инициализатора выполнен до тело конструктора. Следовательно, One полностью построен перед телом Two::Two начинается казнь.

В очереди, One выглядит так:

One::One()
:
Base()
{
string test = "test";
}

А также Base пустой:

Base::Base()
{
}

Так что же происходит, когда Two two; выполняется это:

  1. Base построен
  2. One построен
  3. Автоматическая переменная test создается, инициализируется и уничтожается в контексте One::One
  4. Two::test инициализируется по умолчанию
  5. Two::test присваивается значение «текст»

Обратите внимание, что некоторые из них, особенно шаги 4 & 5 может быть оптимизировано компилятором, если он считает, что это безопасно.

2

Другие решения

Для класса One инициализация One.test будет инициализирована до вызова Base :: Base. Но Two.test будет инициализирован после вызова Base :: Base.

№ базы инициализируются до любой участник.

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

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

В случае Two есть одна деталь, которая, вероятно, имеет значение, и я не уверен, что вы знаете, член test является инициализируется в списке инициализатора Two, до введите тело конструктора, а затем он назначен.

2

Остальные ответили на вопрос.
Но следующая демонстрация может быть полезной.

#include <iostream>
class String
{
public:
String(char const* d)               {std::cout << "String Constructor: " << d << "\n";}
String()                            {std::cout << "String Constructor: Default\n";}
String(String const& rhs)           {std::cout << "String Constructor: Copy\n";}
String& operator=(String const& rhs){std::cout << "String Assignment\n";}
~String()                           {std::cout << "String Destructor\n";}
};

class Base
{
public: Base()
{
std::cout << "Base::Base()\n";
}
};

class One : Base
{
String test = "text";
};

class Two : Base
{
String test;
public: Two()
{
std::cout << "Two::Two\n";
test = "text";
}
};

int main()
{
std::cout << "Trying One\n";
One     one;

std::cout << "==========\n\n\n";
std::cout << "Trying Two\n";
Two     two;

std::cout << "==========\n\n\n";
std::cout << "Trying Base\n";
Base    b;
}

Результат этого:

> ./a.out
Trying One                    // Outside the class about to start
Base::Base()                  // One: Calls the base constructor first Base
String Constructor: text      // One: Constructs its members.
==========Trying Two                    // Outside the class about to start
Base::Base()                  // Two: Calls the base construtor first
String Constructor: Default   // Two: Constructs its members next
Two::Two                      // Two: Now entering the body of the constructor
String Constructor: text      //      Builds a string
String Assignment             //      Calls the assignment constructor.
String Destructor             //      Temporary destroyed.
==========                    //Trying Base
Base::Base()
String Destructor             // Destroys the string in Two
String Destructor             // Destroys the string in One
1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector