我刚读完this answer,如果您有以下代码
class Base
{
public Base()
{
}
}
class One : Base
{
string test = "text";
}
class Two : Base
{
string test;
public Two()
{
test = "text";
}
}
对于第一类,初始化One.test将在调用Base :: Base之前初始化。但是,在调用Base :: Base之后,将初始化Two.test。
我认为这是因为在两种情况下都是
我想我记得初始化列表就在构造函数之前。 那么初始化顺序就是:
Base的领域在哪里?是在分配内存时还是在当前基类的初始化列表之前首先初始化所有字段?
你能想到的列表中还有其他步骤吗?
如果有人能给出一个很好的概述,我将不胜感激。
答案 0 :(得分:2)
对于第一类,初始化One.test将在调用Base :: Base之前初始化。但是,在调用Base :: Base之后,将初始化Two.test。
没有。基础在之前初始化任何成员。
在没有虚拟基础的简化(但最常见)的情况下,对象的初始化顺序是:基于它们在类声明中出现的顺序,然后成员按它们出现的顺序排列声明(不是初始化列表)。只有在完成之后,才会输入构造函数的主体。
在任何其他基础之前初始化,在另一个基础中初始化虚拟基础,这是由从第一个到最后一个声明的基础的深度优先搜索确定的。
在Two
的情况下,有一个细节可能很重要,我不确定您是否知道,成员test
在{的初始化列表中初始化在进入构造函数体之前的<1}},,然后分配它。
答案 1 :(得分:2)
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步和第4步。如果编译器认为这样做是安全的,那么编译器可能会对其进行优化。
答案 2 :(得分:1)
其他人已经回答了这个问题 但是下面的演示可能会有用。
#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