1. 基础概念与核心特性
| 类别 | 内容 | 说明 |
|---|---|---|
| 定义 | 特殊的成员函数,用于对象初始化 | 创建对象 |
| 命名规则 | 与类名完全相同 | 区分大小写 |
| 返回类型 | 无返回类型(连void都没有) | 隐式返回对象本身 |
| 调用时机 | 对象创建时自动调用 | 无需手动调用 |
| 主要职责 | 初始化成员变量、申请资源、执行启动设置 | 确保对象处于有效状态 |
2. 构造函数分类与语法
| 类型 | 语法示例 | 用途 | 关键点 |
|---|---|---|---|
| 默认构造函数 | ClassName(); | 无参创建对象 | 1. 未定义任何构造函数时编译器自动生成 2. 定义其他构造函数后需显式定义 |
| 参数化构造函数 | ClassName(T1 p1, T2 p2); | 带参数初始化 | 支持重载,提供多种初始化方式 |
| 拷贝构造函数 | ClassName(const ClassName& other); | 通过现有对象创建新对象 | 1. 浅拷贝问题 2. 三大法则之一 |
| 移动构造函数 | ClassName(ClassName&& other); | "窃取"临时对象资源 | C++11引入,提升性能 |
| 委托构造函数 | ClassName() : ClassName(0) {} | 构造函数间调用 | C++11引入,避免代码重复 |
| 继承构造函数 | using Base::Base; | 继承基类构造函数 | C++11引入 |
3. 初始化相关重要特性
| 特性 | 语法 | 规则与注意事项 |
|---|---|---|
| 初始化列表 | ClassName() : m1(v1), m2(v2) {} | 1. 必须使用:const成员、引用成员、无默认构造的类成员 2. 推荐使用:效率高于构造函数体内赋值 3. 顺序:按成员声明顺序初始化,与列表顺序无关 |
| explicit关键字 | explicit ClassName(int x); | 1. 防止单参数构造函数的隐式转换 2. 提高代码安全性 |
| 类内初始化 | int count = 0; std::string name{"default"}; | C++11引入,提供默认值 |
| 默认/删除 | = default; = delete; | 显式控制编译器生成行为 |
4. 编译器行为与自动生成规则
| 函数类型 | 生成条件 | 默认行为 |
|---|---|---|
| 默认构造函数 | 用户未定义任何构造函数时 | 1. 调用基类默认构造 2. 调用成员默认构造 3. 不初始化内置类型 |
| 拷贝构造函数 | 用户未定义拷贝操作时 | 逐成员浅拷贝 |
| 拷贝赋值运算符 | 用户未定义拷贝赋值时 | 逐成员浅赋值 |
| 移动构造函数 | 用户未定义拷贝/移动/析构时 | 逐成员移动 |
| 析构函数 | 用户未定义析构函数时 | 非虚函数,调用基类和成员的析构函数 |
5. 继承体系中的构造函数
| 场景 | 调用顺序 | 注意事项 |
|---|---|---|
| 普通继承 | 基类 → 成员对象 → 派生类 | 默认调用基类默认构造函数 |
| 显式调用基类构造 | Derived() : Base(args) {} | 在初始化列表中指定基类构造函数 |
| 虚函数调用 | 构造函数中调用虚函数 | 不会发生多态,调用当前类版本 |
| 异常处理 | 基类构造失败 | 整个对象构造失败,派生类部分不会被构造 |
6. 资源管理与异常安全
| 原则 | 内容 | 最佳实践 |
|---|---|---|
| RAII原则 | 资源获取即初始化 | 使用智能指针、容器等RAII对象 |
| 三大法则 | 需要自定义析构函数、拷贝构造、拷贝赋值之一时,通常需要三者全部自定义 | 确保资源正确管理 |
| 异常安全 | 构造函数中异常的处理 | 1. 使用RAII避免资源泄漏 2. 避免在构造函数中做可能失败的操作 |
| 自赋值检查 | 拷贝赋值运算符中的if(this != &other) | 防止自赋值导致的资源错误 |
7. 常见误区与陷阱
| 误区类型 | 问题描述 | 解决方案 |
|---|---|---|
| 缺失默认构造 | 定义带参构造后,无参对象创建失败 | 显式定义默认构造函数 |
| 最恼人解析 | ClassName obj(); 被解析为函数声明 | 使用 ClassName obj; 或 ClassName obj{}; |
| 浅拷贝问题 | 指针成员浅拷贝导致重复释放 | 实现深拷贝或使用智能指针 |
| 初始化顺序混淆 | 初始化列表顺序与成员声明顺序不一致 | 保持两者顺序一致 |
| 未初始化内置类型 | 编译器生成的默认构造不初始化内置类型 | 在初始化列表或类内初始化中显式初始化 |
| 委托构造函数循环 | 构造函数间循环委托 | 避免循环委托设计 |
| 移动语义未使用 | 应使用移动的场合进行了拷贝 | 定义移动操作,在适当时机使用std::move |
8. 编译器特定行为与调试
| 编译器 | 特性/标志 | 用途 |
|---|---|---|
| GCC/Clang | -Weffc++ -Wreorder -fno-elide-constructors | 检测准则违反、顺序警告、禁用复制消除 |
| MSVC | /W4 __declspec(noinline) | 提高警告级别、阻止内联用于调试 |
| 通用调试 | __PRETTY_FUNCTION__ (GCC/Clang)__FUNCSIG__ (MSVC) | 获取函数签名用于调试输出 |
9. 现代C++最佳实践检查清单
| 检查项 | 说明 |
|---|---|
| 是否需要显式定义默认构造函数? | 特别是定义了其他构造函数后 |
| 初始化列表顺序与成员声明顺序是否一致? | 避免混淆 |
| const成员和引用成员是否正确初始化? | 必须在初始化列表中初始化 |
| 是否需要自定义拷贝控制函数? | 根据资源管理需求决定 |
| 拷贝构造函数是否实现了正确的深拷贝? | 如类包含原始指针等资源 |
| 拷贝赋值运算符是否处理了自赋值? | if (this != &other) |
| 基类构造函数是否正确调用? | 在派生类初始化列表中 |
| 是否避免了在构造函数中调用虚函数? | 不会发生多态行为 |
| 资源管理是否使用RAII原则? | 优先使用智能指针等 |
| 单参数构造函数是否标记为explicit? | 防止意外隐式转换 |
| 是否考虑了移动语义的优化? | C++11及以上版本 |
| 异常安全性是否得到保证? | 特别是资源申请操作 |
10. 设计模式与高级用法
| 模式/用法 | 构造函数角色 | 实现要点 |
|---|---|---|
| 单例模式 | 私有构造函数 | 防止外部实例化,通过静态方法获取实例 |
| 工厂模式 | 保护/私有构造函数 | 通过工厂类创建对象,控制构造过程 |
| PImpl惯用法 | 在实现类中正常构造 | 分离接口与实现,减少编译依赖 |
| CRTP | 基类模板中的构造 | 奇特的递归模板模式,实现编译期多态 |
9303

被折叠的 条评论
为什么被折叠?



