C++ 继承和初始化顺序

标签 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; 
}

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

warning: field 'b' will be initialized after base 'B' [-Wreorder] C(int a=10, int b=20):a(a), b(a*b), B(b) {} ~C() { cout << "C::~" << endl; } ^ 1 warning generated.

和以下输出:

A::A, a=20
B::B
A::A, a=10
A::A, a=200
B::B
C::~
B::~
A::~
A::~
B::~
A::~

销毁顺序有点清楚(最后构造 - 首先销毁),但我似乎无法理解构造顺序/模式。我错过了什么?对我收到的警告 进行澄清会非常有帮助。另外,如果您可以向我推荐有关该特定主题的额外阅读 Material 。

谢谢。

最佳答案

初始化顺序在标准中有明确定义:

12.6.2./10: In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

— Finally, the compound-statement of the constructor body is executed.

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

然后,AB被初始化,C的成员被初始化,首先从a开始使用默认参数 10,然后使用 b(200)。由于b 是一个B,它首先需要初始化它自己的基A。这样就可以完成b的初始化了。最后完成C的初始化。

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

12.4/7: Bases and members are destroyed in the reverse order of the completion of their constructor.

警告注意事项:

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

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

关于C++ 继承和初始化顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28529185/

相关文章:

c++ - 如何将 SQLite 嵌入到 C++ 项目中

c++ - SFML 2.0 碰撞类

python类的继承顺序

Python 多重继承和 super()

c++ - 我可以从内存流加载库吗?

c++ - C++ 中字符串和 ofstream 参数的类似 Java 的 null

c++ - 模板接口(interface) - 通过引用或值使用

C# 基类和 2 个派生类初始化

ios - 子类中 self 和 super 之间的混淆

c++ - 如何声明任何继承类的实例?