我正在为期末考试而学习。我偶然发现了前几年的这个问题,我似乎无法完全理解发生了什么。 根据此代码,确定输出
#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;
}
我尝试编译代码,然后收到警告:
警告:字段'b'将在基数'B'后初始化 [-Wreorder] C(int a = 10,int b = 20):a(a),b(a * b),B(b){} ~C(){cout&lt;&lt; “C ::〜”&lt;&lt; ENDL; } 生成^ 1警告。
以及以下输出:
A::A, a=20
B::B
A::A, a=10
A::A, a=200
B::B
C::~
B::~
A::~
A::~
B::~
A::~
破坏秩序有点清晰(最后构造 - 首先被破坏),但我似乎无法看到施工顺序/模式。我错过了什么?我收到的警告的说明会更有帮助。另外,如果您可以向我推荐有关此特定主题的额外阅读材料。
谢谢。
答案 0 :(得分:3)
这一行:
C(int a=10, int b=20):a(a), b(a*b), B(b) {}
应该是:
C(int a=10, int b=20): B(b), a(a), b(a*b) {}
在C ++中,初始化顺序是固定的。对于您的类型C
,它始终为:
B
A a;
B b;
在初始化列表中,您对其进行了不同的排序。因此,如果您希望初始化程序列表的顺序无关紧要,您的编译器会发出警告。
答案 1 :(得分:2)
初始化顺序在标准中精确定义:
12.6.2./10:在非委托构造函数中,初始化按以下顺序进行:
- 首先,仅适用于构造函数 最派生类(1.8),虚拟基类是 按照它们在深度优先从左到右的顺序初始化 遍历基类的有向无环图,其中 “从左到右”是基类出现的顺序 派生类base-specifier-list。
- 然后,直接基类 按照声明顺序初始化,因为它们出现在 base-specifier-list(无论mem-initializers的顺序如何)。
- 然后,非静态数据成员按其顺序初始化 在类定义中声明(再次无论顺序如何) 记忆初始化者)。
- 最后,复合声明了 构造函数体被执行。
因此,当你初始化C时,它的基类首先被初始化,即B
默认为20,它本身需要A
首先用20初始化。只有这样才能初始化B
完成。
然后,A
和B
被初始化,C
的成员被初始化,首先使用默认参数10 a
开始,然后使用b(200)
}。由于b
是B
,它首先需要初始化自己的基础A
。然后可以完成b
的初始化。最后,C
的初始化完成。
顺便说一句,它不是问题的一部分,但请记住你的考试:
12.4 / 7:基础和成员按照构造函数完成的相反顺序销毁。
有关警告的说明:
我的编译器没有生成此警告。没有理由,因为mem-initilizer B(b)
明确使用了你的consturctor的参数b
。它只是一个假设,但我怀疑你的编译器会产生误报,因为b
也是一个成员的名字(在调用base时确实不会初始化)。如果我没错,以下更改不应再发出警告:
C(int a=10, int bbb=20):a(a), b(a*bbb), B(bbb) { cout << "C::C" << endl;}