继承构造函数不初始化派生类新增成员,其按声明顺序依默认成员初始化器或默认初始化规则处理;无默认初始化器的内置类型值未定义,const/引用及无默认构造函数成员必须显式初始化。

继承构造函数时,派生类新增成员的初始化规则
用 using Base::Base 继承构造函数后,派生类新增的成员**不会被继承来的构造函数自动初始化**;它们按声明顺序、依据是否有默认成员初始化器(default member initializer)决定行为:有则用它初始化,没有则默认初始化(内置类型不赋值,值未定义)。
-
int x;这类无默认初始化器的内置类型成员:不执行任何初始化,x值是未定义的 -
int y = 42;或std::string s = "hello";:每次构造对象时都会执行右侧表达式 -
const int z = get();:合法,get()在基类子对象初始化完成后、构造函数体执行前调用 - 若新增成员是自定义类型且无默认构造函数(如
NonDefault obj;),则继承构造函数无法使用——编译报错,因为该成员无法被默认初始化
为什么不能在继承构造函数里加初始化列表
继承构造函数本质是“转发”,它没有自己的函数体,也不允许写初始化列表。你写 using Base::Base; 后,Derived(int x) : Base(x), member(0) 是非法语法,编译器直接拒绝。
- 错误示例:
struct D : B { using B::B; int m; D(int x) : B(x), m(0) {} };→ 编译失败,C++ 标准禁止这种写法 - 正确做法只有两个:要么给
m加默认初始化器(int m = 0;),要么显式定义自己的构造函数并写初始化列表 - 注意:即使基类构造函数接受多个参数,派生类也无法借机“顺带”初始化自己的成员——继承不是扩展,而是复用
继承构造函数 + 新增 const / 引用成员的坑
如果派生类新增了 const 成员或引用成员,又只靠继承构造函数,那基本会编译失败——因为这些类型必须在初始化列表中初始化,而继承构造函数不提供初始化列表。
-
const int c;:没默认初始化器 → 默认初始化不合法 → 编译错误 -
const int c = 1;:合法,靠默认成员初始化器兜底 -
int& ref;:不可能有默认初始化器(引用必须绑定),也无法被默认初始化 → 必须放弃继承,改用显式构造函数 - 同理,含无默认构造函数的成员(如
std::unique_ptr<t> p;</t>)也必须显式初始化,否则继承构造函数不可用
什么时候该放弃继承构造函数
当派生类新增成员需要精确控制初始化逻辑(比如依赖参数、条件分支、异常安全处理),或存在 const / 引用 / 无默认构造函数的成员时,using Base::Base 就不够用了。
立即学习“C++免费学习笔记(深入)”;
- 典型信号:编译报错类似
member 'x' must be initialized by mem-initializer in constructor - 替代方案是显式定义构造函数,并在初始化列表中同时调用基类构造和初始化新增成员,例如:
D(int a, int b) : Base(a), x(b), y(b * 2) {} - 注意:此时你失去了“自动继承所有基类构造函数”的便利,但换来了完全控制权——这是设计取舍,不是缺陷
实际中最容易忽略的是:默认成员初始化器的求值时机发生在基类子对象初始化之后、构造函数体之前。这意味着你可以安全地在 y = func(); 中调用依赖基类状态的函数,但不能反过来让基类构造依赖派生类成员——那个阶段它们还没活过来。


















