You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++继承构造函数初始化顺序及参数传递疑问咨询

继承构造函数的初始化行为解析

示例代码

#include <iostream>
#define print(X) std::cout << X << std::endl

struct B1 {
    B1(int _i = 5): i(_i) { print("B1 constructor"); };
    int i;
};

struct B2 {
    B2(int _j = 7): j(_j) { print("B2 constructor"); }
    int j;
};

struct D : B2, B1 {
    using B1::B1;
};

int main(void)
{
    D d = D{10};
    print("B1::i = " << d.i);
    print("B2::j = " << d.j);
}

程序输出

B2 constructor
B1 constructor
B1::i = 10
B2::j = 7

相关标准条款引用

根据§11.9.4[class.inhctor.init]/1条款:
当调用类型B的构造函数初始化不同类型D的对象时(即该构造函数是被继承的([namespace.udecl])),初始化过程如同使用默认的默认构造函数初始化D对象以及每个从中继承构造函数的基类子对象,除非如果基类子对象是D对象初始化的一部分,则B子对象由继承的构造函数初始化([class.base.init])。如果B子对象不是D对象初始化的一部分,则省略继承构造函数的调用,包括任何参数的求值。完整的初始化被视为单个函数调用;特别地,除非被省略,继承构造函数的参数初始化会在D对象任何部分的初始化之前排序。

疑问与解答

我理解D从B1继承了构造函数B1(int),该函数负责初始化B1子对象,且参数会在D对象任何部分初始化前完成求值,重载决议选择了D::B1(int)来初始化B1::i。但输出显示两个问题:

  1. B2的构造函数先被调用,执行顺序早于B1;
  2. B2的j用默认参数7初始化,而非传入的10。

问题1:为什么B2的j用默认参数7初始化?

using B1::B1;仅会将B1的构造函数继承到派生类D中,这个继承的构造函数只负责初始化它所属的基类B1的子对象。对于D的其他基类(比如B2),会按照默认规则初始化——调用B2的默认构造函数(这里B2的构造函数带有默认参数_j=7,符合默认构造函数的定义)。继承的构造函数不会将参数传递给非来源基类,因此传入的10只会用于初始化B1的i,B2的j只能使用默认参数值。

问题2:为什么B2的构造函数先执行?

C++标准明确规定,基类的初始化顺序由它们在派生类声明中的出现顺序决定,与构造函数的继承来源、成员初始化列表顺序无关。在struct D : B2, B1中,B2被写在B1前面,因此初始化D对象时,会先初始化B2子对象,再初始化B1子对象。对应的标准条款是§11.9.3[class.base.init]/13:

在非委托构造函数中,初始化的顺序如下:

  • 首先,按照基类在派生类定义中出现的顺序,依次初始化直接基类(不考虑成员初始化列表的顺序)。

内容的提问来源于stack exchange,提问作者mada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:13:15