委托构造函数必须在初始化列表中调用且唯一,不能在函数体内或混用其他初始化;被委托者函数体仍执行;explicit限制仍生效;禁止循环委托和跨类委托;重载解析不考虑默认参数。

委托构造函数的写法必须在初始化列表中调用
委托构造函数不是普通函数调用,它必须出现在构造函数的初始化列表里,且只能是唯一一条初始化语句(不能和其他成员初始化混用)。编译器会直接跳过被委托构造函数体内的逻辑,只执行其初始化列表和函数体——但注意:被委托者的函数体仍会被执行。
常见错误是写成 this->A(1, 2) 或在函数体内调用 A(1, 2),这会创建临时对象而非委托,导致意外的拷贝或未定义行为。
- 正确写法:
A() : A(42) {}(无参委托有参) - 错误写法:
A() { A(42); }(这是局部临时对象构造,不是委托) - 错误写法:
A() : x(0), A(42) {}(初始化列表中混用,编译失败)
被委托构造函数不能是 explicit 的(除非显式调用)
如果被委托的构造函数加了 explicit,那么委托语法本身不会报错,但会导致某些隐式转换场景失效。更关键的是:委托目标若为 explicit,你无法通过“带参数的构造函数调用”来触发委托(比如在 std::vector<a> v(1)</a> 中),因为那需要隐式转换。
典型陷阱是定义了 explicit A(int) 后,又写 A() : A(0) {} —— 这段代码本身合法,但如果你后续想用 A a = 5; 就会失败,而委托构造的存在容易让人误以为“这个类支持 int 构造”,其实限制仍在。
立即学习“C++免费学习笔记(深入)”;
-
explicit A(int)+A() : A(0) {}→ 委托合法,但A a = 1;编译失败 - 去掉
explicit才能支持拷贝初始化中的隐式转换 - 委托不改变原构造函数的访问属性或 explicit 性质
委托链不能形成循环,且不能跨继承层级
C++ 不允许构造函数 A 委托给 B,B 又委托回 A;编译器会在编译期检测并报错,错误信息通常是 delegating constructor call would cause infinite loop。另外,委托只能发生在同一类内,子类不能委托给父类构造函数(那是继承初始化列表的工作)。
容易混淆的点是:有人试图用委托替代 : Base(x),这是无效的。基类初始化必须显式写在初始化列表中,委托不能绕过它。
- 禁止:
B() : B() {}或A() : B() {}(不同类) - 禁止:
A(int) : A() {}, A() : A(0) {}(循环) - 正确替代基类初始化的方式仍是:
Derived() : Base(42), member(1) {}
委托构造与默认参数、重载解析的关系
委托构造发生时,重载解析照常进行,但仅限于当前类的构造函数集合。如果有多个可匹配的构造函数,编译器不会“自动选最简那个”,而是严格按参数类型和数量匹配——这意味着默认参数在委托调用中**不参与重载决策**,除非你显式写出。
例如,定义了 A(int x = 0) 和 A(double),然后写 A() : A() {} 是非法的(没有无参构造函数),而 A() : A(0) {} 会调用 A(int),哪怕 0 也能转成 double,因为 int 是精确匹配。
- 委托调用不考虑默认参数“补全”,必须提供可精确/优先匹配的实参
- 避免依赖隐式转换做委托目标选择,容易因新增重载而突然编译失败
- 调试时注意:断点打在被委托构造函数体内是有效的,但初始化列表里的其他成员不会被重复初始化










