C++ 继承和初始化顺序

Air*_*ezx 2 c++ inheritance

我正在为期末考试而学习。我在前几年偶然发现了这个问题,但我似乎无法完全理解发生了什么。 给定此代码,确定输出

#include <iostream>
using namespace std;
struct A {
    A(int a): _a(a) {cout << "A::A, a=" << _a << endl;} 
    ~A() { cout << "A::~" << endl; }
    int _a;
};

struct B: public A
{
    B(int b):A(b) { cout << "B::B" << endl; }
    ~B() { cout << "B::~" << endl; } 
};

struct C: public B
{
    A a;
    B b;
    C(int a=10, int b=20):a(a), b(a*b), B(b) {} 
    ~C() { cout << "C::~" << endl; }
};

int main() {
    C allTogetherNow;
    return 0; 
}
Run Code Online (Sandbox Code Playgroud)

我尝试编译代码,但收到警告:

警告:字段“b”将在基“B”之后初始化 [-Wreorder] C(int a=10, int b=20):a(a), b(a*b), B(b) {} ~ C() { cout << "C::~" << endl; } ^ 生成 1 个警告。

和以下输出:

A::A, a=20
B::B
A::A, a=10
A::A, a=200
B::B
C::~
B::~
A::~
A::~
B::~
A::~
Run Code Online (Sandbox Code Playgroud)

销毁顺序有点明确(最后构建 - 首先销毁),但我似乎无法掌握构建顺序/模式..我错过了什么?对我收到的警告进行澄清将会非常有帮助。另外,您是否可以向我推荐有关该特定主题的额外阅读材料。

谢谢。

Chr*_*phe 5

标准中精确定义了初始化顺序:

\n\n
\n

12.6.2./10: 在非委托构造函数中,初始化按以下顺序进行:

\n\n

\xe2\x80\x94 首先,并且仅对于最派生类 (1.8) 的构造函数\n,虚拟基类按照它们在深度优先从左到右\n 遍历中出现的顺序进行初始化。基类的有向无环图,其中 \n \xe2\x80\x9cleft-to-right\xe2\x80\x9d 是派生类基说明符列表中基类的出现顺序。

\n\n

\xe2\x80\x94 然后,直接基类按照它们出现在基说明符列表中的声明顺序进行初始化(无论 mem 初始化程序的顺序如何)。

\n\n

\xe2\x80\x94 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样与内存初始化程序的顺序无关)。

\n\n

\xe2\x80\x94 最后,执行构造函数体的复合语句。

\n
\n\n

所以当你初始化C时,它的基类首先被初始化,即B默认为20,它本身需要A先用20初始化。只有这样初始化才B完成。

\n\n

然后,AB初始化时, 的成员C也被初始化,首先从a默认参数 10 开始,然后从b(200)。与ba一样B,它首先需要初始化自己的基数Ab然后就可以完成初始化了。最后初始化C完成。

\n\n

顺便说一句,这不是问题的一部分,但请记住考试时:

\n\n
\n

12.4/7:基类和成员按照其构造函数完成的相反顺序被销毁。

\n
\n\n

关于警告的注意事项:

\n\n

我的编译器不会生成此警告。没有理由这样做,因为内存初始化器B(b)显然使用了构造函数的参数b。这只是一个假设,但我怀疑你的编译器会提出误报,因为b它也是成员的名称(在调用基类时确实不会初始化)。如果我是对的,以下更改不应再发出警告:

\n\n
 C(int a=10, int bbb=20):a(a), b(a*bbb), B(bbb) { cout << "C::C" << endl;} \n
Run Code Online (Sandbox Code Playgroud)\n