//This program is taken from http://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/
#include <iostream>
using namespace std;
class A
{
public:
A(int nValue)
{
cout << "A: " << nValue << endl;
}
};
class B: public A
{
public:
B(int nValue, double dValue)
: A(nValue)
{
cout << "B: " << dValue << endl;
}
};
int main()
{
B bClass(5, 4.3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行这个:
$g++ inherit.cpp -o inherit
$ ./inherit
A: 5
B: 4.3
Run Code Online (Sandbox Code Playgroud)
这是预料之中的.
但是当我改变class B这个:
class B: public A
{
int something;
public:
B(int nValue, double dValue)
: something(nValue), A(nValue)
{
cout << "B: " << dValue << endl;
cout << "B.something: " << something << endl;
}
};
Run Code Online (Sandbox Code Playgroud)
输出是:
$ ./inherit
A: 5
B: 4.3
B.something: 5
Run Code Online (Sandbox Code Playgroud)
当编译器通过B的初始化列表时,它是否仅搜索基类构造函数并跳转到它而不执行其他语句(something(nValue))
或执行所有语句,直到它找到BaseClass构造函数并且根本不执行构造函数body直到Base Class构造函数完成执行?
换句话说,在第一次遇到语句时B.something是设置值还是在调用A(nValue)之前保持未初始化?nValuesomething(nValue)
一个类的实例的全部子对象和非静态成员对象在固定的顺序被初始化,即在其声明的顺序(它是:首先,以在子对象(例如A,B,C对class Foo : A, B, C),则非静态成员对象).
在初始化列表中列出初始值设定项的顺序不会影响此行为; 但是,您应该始终以正确的顺序编写IL,以避免出现意外并使代码尽可能易于阅读.
通常应该避免让一个对象初始值设定项依赖于另一个对象,但有时可能是必要的.如果可能,只需重用构造函数参数.例:
struct Foo {
int a;
int b;
Foo(int a_, int b_) : a(a_), b(a) { } // not so good, depends on order!
Foo(int a_, int b_) : a(a_), b(a_) { } // better, always works
};
Run Code Online (Sandbox Code Playgroud)
现在想象一下,我们struct Foo : Bar可能会想要为Fooas 编写一个初始化器a(a_), b(a), Bar(a, b).那将是一场灾难.按顺序编写IL会使这变得不可能:Bar(a_, b_), a(a_), b(a_).