Я просто прочитал в этом ответе, что если у вас есть следующий код
class Base
{
public Base()
{
}
}
class One : Base
{
string test = "text";
}
class Two : Base
{
string test;
public Two()
{
test = "text";
}
}
Для класса One инициализация инициализации инициализируется инициализацией инициализации перед вызовом Base :: Base. Но Two.test будет инициализирован после вызова Base :: Base.
Я предполагаю, что это происходит потому, что в обоих случаях это
Я думаю, что я помню, что списки инициализации находятся непосредственно перед конструктором. Итак, порядок инициализации тогда:
И куда входят поля Базы? Все ли поля инициализируются первым, когда выделена память или непосредственно перед списком инициализации текущего базового класса?
И есть ли другие шаги в списке, о котором вы можете думать?
Я был бы признателен, если бы кто-нибудь мог дать хороший обзор.
Инициализация C++ происходит в следующем порядке:
Инициализация базовых классов с этапа 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;
выполняется:
Base
построена.One
построенtest
переменной строится, инициализируется и уничтожается в контексте One::One
Two::test
инициализируются по умолчаниюTwo::test
присваивается значение "text"Обратите внимание, что некоторые из них, особенно шаги 4 и 5, могут быть оптимизированы компилятором, если он считает это безопасным.
class Two : public One
и class One : public Base
One
не совсем так, как изображено в этом ответе. Нет test
локальной переменной, а есть переменная-член со значением инициализатора. Это переводится компилятором в: One() : Base(), test("test") {}
Для класса One инициализация инициализации инициализируется инициализацией инициализации перед вызовом Base :: Base. Но Two.test будет инициализирован после вызова Base :: Base.
Нет. Базы инициализируются перед любым членом.
В упрощенном (и в то же время наиболее распространенном) случае без виртуальных оснований порядок инициализации объектов: основы в том порядке, в котором они появляются в объявлении класса, затем члены в том порядке, в котором они появляются в объявлении ( а не список инициализации). Только после этого вводится тело конструктора.
Виртуальные базы инициализируются перед любой другой базой, в другой, которая определяется первым поиском глубины, начиная от первой до последней объявленной базы.
В случае Two
есть одна деталь, которая, вероятно, имеет значение, и я не уверен, что вы знаете, test
участника инициализируется в списке инициализаторов из Two
, прежде чем вводить тело конструктора, а затем назначается.
Остальные ответили на вопрос.
Но следующая демо может быть полезна.
#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