当前位置: 首页 > news >正文

C++中委托构造函数(delegating constructor)详解和注意事项

C++11 引入的委托构造函数(delegating constructor)


一、概念与语法

  • 委托构造指一个构造函数在其初始化列表中,直接调用同类的另一个构造函数来完成部分(或全部)初始化。

  • 语法形式:

    class A {
    public:A(int x, int y): _x(x), _y(y){ /* 主构造逻辑 */ }// 委托构造:将初始化委托给 A(int,int)A(): A(0, 0)    // 委托到上面带参构造{ /* 可留空或做额外逻辑 */ }A(int x): A(x, 0)    // 委托到 A(int,int){ }
    private:int _x, _y;
    };
    
  • 只有一个委托目标可写在初始化列表的最开头,而且初始化列表中不能再出现成员或基类初始化,否则编译失败。


二、使用场景

  1. 消除重复代码
    多个构造函数共享“公共初始化”逻辑时,将初始化集中在一个“主构造函数”中,其它构造函数只负责传参及少量收尾工作。
  2. 统一资源获取/设置
    比如打开文件、分配内存、注册回调等步骤应只在一处编写,避免修改遗漏。
  3. 与默认参数不可兼得时的替代
    对于需要在不同分支做不同预处理,再调用主构造,委托构造比重载+默认参数更灵活。

三、执行顺序

假设有三种构造函数链:

A()      : A(1)       { std::cout<<"A() body\n"; }
A(int x) : A(x, 2)    { std::cout<<"A(int)\n"; }
A(int x, int y)       { std::cout<<"A(int,int)\n"; }

A() 时,调用流程为:

  1. 调用 A() 的初始化列表,委托到 A(int)
  2. A(int) 的初始化列表,委托到 A(int,int)
  3. 进入 A(int,int)——执行成员和基类的初始化,再执行它的函数体;
  4. 返回 A(int),执行其函数体;
  5. 返回 A(),执行其函数体。

输出示例:

A(int,int)
A(int)
A()

四、限制与注意事项

  1. 只能委托同一类内部的另一个构造
    不能跨类委托,也不能在同一初始化列表里同时委托和初始化成员/基类。

  2. 禁止循环委托
    A 委托到 B,B 又委托到 A,会导致无限递归。编译器会报错。

  3. 初始化列表顺序不变
    即使在委托链中先后出现,基类子对象仍旧最先初始化,接着按声明顺序初始化成员。

  4. 与默认成员初始化配合

    • 如果成员在类内已给出默认初始化,主构造函数或其委托目标可覆盖它;
    • 非委托目标构造函数不要在初始化列表写成员初始化,以免与委托冲突。
  5. 异常安全
    所有初始化都在主构造函数里发生,如果主构造抛异常,已初始化的成员会被正确析构。

  6. 可与 explicit / 隐式转换结合
    可以给委托构造函数加 explicit,防止意外隐式构造。


五、综合示例

#include <iostream>
#include <string>class Logger {
public:Logger(const std::string& name, int level): _name(name), _level(level){std::cout << "Logger("<<_name<<","<<_level<<")\n";}// 委托到 Logger(name, 0)Logger(const std::string& name): Logger(name, 0){std::cout << "Logger(name)\n";}// 委托到 Logger("default", 0)Logger(): Logger("default"){std::cout << "Logger()\n";}private:std::string _name;int         _level;
};int main() {Logger L1;                 // default 构造Logger L2("network");      // name 构造Logger L3("db", 3);        // 主构造return 0;
}

输出:

Logger(default,0)
Logger(name)
Logger()
Logger(network,0)
Logger(name)
Logger(db,3)

六、最佳实践

  1. 明确主构造函数
    将最完整、最“重”初始化的构造函数作为主构造,保持其逻辑最全。
  2. 文档注释
    在头文件注明哪个构造是“委托”,以及委托的入口/出口含义。
  3. 避免成员初始化冲突
    除主构造外,其它构造不在初始化列表中出现成员/基类初始化,以免编译器报“不能与委托共存”。
  4. 链式委托深度适中
    链太深可能影响可读性和调试,建议不超过 2~3 级
  5. 与默认参数配合
    对于可省略的参数,也可用默认参数+委托构造混合方式,让 API 既简洁又灵活。

相关文章:

  • elementUI 循环出来的表单,怎么做表单校验?
  • InforSuite RDS 与django结合
  • React事件机制
  • 解决 Conda 安装 PyTorch 1.1.0 报错:excluded by strict repo priority(附三种解决方案)
  • [特殊字符]川翔云电脑:重新定义云端算力新纪元
  • 【爬虫】DrissionPage-3
  • 力扣-49.字母异位词分组
  • 10.2 LangChain v0.3全面解析:模块化架构+多代理系统如何实现效率飙升500%
  • 如何安全擦除 SSD 上的可用空间
  • 牛客网NC231954:斐波那契数列 (简单的数列问题)
  • Ubuntu离线安装Minio
  • DeepSeek模型架构详解:从Transformer到MoE
  • ‌JMeter聚合报告中的任务数和并发数区别
  • 【AI News | 20250515】每日AI进展
  • 数据结构——例题3
  • Function Calling
  • 【LLIE专题】基于码本先验与生成式归一化流的低光照图像增强新方法
  • OpenHarmony 5.1.0 Release目录结构详细解析(3级目录)
  • 解读RTOS 第八篇 · 内核源码解读:以 FreeRTOS 为例
  • AAC 协议
  • 一周文化讲座|“我的生命不过是温柔的疯狂”
  • 九江宜春领导干部任前公示,3人拟提名为县(市、区)长候选人
  • 中办、国办关于持续推进城市更新行动的意见
  • 美将解除对叙利亚制裁,外交部:中方一贯反对非法单边制裁
  • 美国务院批准向土耳其出售导弹及相关部件,价值3.04亿美元
  • 风雨天涯梦——《袁保龄公牍》发微