C++中如何结合默认成员初始化与委托构造函数消除代码重复
C++中默认成员初始化与委托构造函数的兼容方案
首先明确结论:C++完全支持同时使用默认成员初始化(类内非静态成员初始值设定项)和委托构造函数,你之前的写法无法编译是因为违反了委托构造的语法规则,而非两种特性不兼容。
语法规则说明
C++标准对委托构造有硬性语法约束:如果一个构造函数在成员初始化列表中调用了其他构造函数(即作为委托方),那么它的初始化列表里只能存在这一个对目标构造函数的调用,不能再写其他成员初始化、基类初始化项。你写的: foo_{foo}, bar_{bar}, Widget()同时包含成员初始化和委托调用,因此无法通过编译。
优雅实现方案
不需要额外封装init函数,只需要反转委托方向即可,同时完整保留默认成员初始化的兜底作用,完全消除代码重复:
- 把包含公共构造逻辑的双参构造作为委托终点,在它的初始化列表里完成传入参数的成员赋值,构造函数体内放所有公共逻辑
- 无参构造直接委托给双参构造,传入默认值即可
- 类内的默认成员初始化完全保留,作为后续新增构造函数时的初始化安全网,避免出现成员未初始化的问题
具体实现代码如下:
class Widget { public: // 无参构造直接委托给双参构造,传入默认值 explicit Widget() : Widget(42, 13) {} explicit Widget(int foo, int bar); private: Gadget * gadget_; // 默认成员初始化完全保留,作为兜底初始化规则 int foo_{42}; int bar_{13}; }; // 双参构造是唯一实现完整构造逻辑的位置,无代码重复 Widget::Widget(int foo, int bar) : foo_{foo} , bar_{bar} { ComplicatedConstructionStandIn::frobnicate_gadget(&gadget_); TheConstructorHasManyLines(foo_, gadget_); ItDoesMultipleThings(bar_); }
方案说明
- 成员初始化顺序完全符合类内声明顺序:
gadget_最先完成默认初始化,之后是foo_、bar_,和原有代码的初始化顺序、执行逻辑完全一致,不会引入顺序相关bug - 类内默认成员初始化依然生效:如果后续新增其他构造函数时忘记初始化
foo_或bar_,编译器会自动使用42、13作为初始值,保留了默认成员初始化的安全价值 - 没有init函数的固有缺陷:所有逻辑都在构造阶段完成,支持const成员、引用成员的初始化,符合C++构造语义
- 代码零重复:所有公共构造逻辑只在双参构造中写一次,无冗余代码
如果需要避免默认值在两处(类内初始化、无参构造传参)维护的问题,可以把默认值定义为类内静态常量,让默认成员初始化和无参构造传参都引用同一个常量,后续修改默认值只需要改一处即可。
内容的提问来源于stack exchange,提问作者Jan Hošek
相关产品推荐
相关产品推荐

