C++ 类编译器默认生成的十大特殊成员函数
C 类编译器默认生成的十大特殊成员函数一、完整列表C98 ~ C11 统一标准如果类没有手动声明对应函数编译器会隐式自动生成默认构造函数无参构造拷贝构造函数复制构造拷贝赋值运算符operator析构函数移动构造函数C11 新增移动赋值运算符operatorC11 新增前4个是C98就有后2个移动语义是C11引入。二、逐个详解生成规则、触发条件、禁用场景1. 默认构造函数T()生成条件类没有任何自定义构造函数有参、无参都算自定义编译器生成空无参构造。structA{intx;};// 编译器生成A::A() {}A a;// 合法调用默认构造不生成的情况只要写了任意构造函数哪怕带参数编译器不再生成默认构造structA{A(int){}// 自定义构造无默认构造};A a;// 编译报错特殊限制类含const成员/引用成员自动默认构造函数会被删除无法初始化。成员无默认构造本类默认构造被删除。2. 拷贝构造函数T(const T)生成条件没有手动声明拷贝构造编译器生成浅拷贝版本逐成员拷贝值拷贝。structA{intx;};// 自动生成 A(const A other) : x(other.x) {}A a1;A a2a1;// 调用拷贝构造不生成/被删除场景手动写了拷贝构造类包含不可拷贝成员引用、const成员、unique_ptr、无拷贝构造的成员基类拷贝构造被删除/私有。3. 拷贝赋值T operator(const T)生成规则无手动重载赋值生成逐成员赋值浅拷贝。A a1,a2;a2a1;// 调用自动拷贝赋值自动删除场景有 const / 引用成员引用不能重新赋值成员不可赋值unique_ptr等基类赋值运算符被删除。4. 析构函数~T()生成条件没有手动写析构编译器生成空析构structA{intx;};// 自动生成 ~A(){}对象销毁时调用特殊规则哪怕写了其他构造析构依然会默认生成析构不会被自动删除只有手动~A() delete;才禁用基类析构建议加virtual否则多态释放内存泄漏编译器不会自动virtual。5. 移动构造T(T)C11生成前提全部满足才生成没有自定义拷贝构造、拷贝赋值、移动构造、移动赋值、析构所有非静态成员、基类都支持移动构造。作用转移资源所有权std::move性能优于拷贝。触发删除只要手动写了拷贝构造/析构等任一函数编译器不再生成移动构造。6. 移动赋值T operator(T)C11生成规则和移动构造完全一致只要手动定义拷贝/析构等就不会自动生成。三、记忆速记三/五法则1. C98 三法则Rule of Three如果你手动定义了下面任意一个建议手动写出另外两个析构函数拷贝构造拷贝赋值运算符原因通常是管理堆内存/资源默认浅拷贝会双重释放、内存泄漏。2. C11 五法则Rule of Five扩展两条移动函数手动定义析构/拷贝构造/拷贝赋值任一编译器不会自动生成移动构造、移动赋值此时资源类建议显式定义/禁用全部5个特殊函数默认构造拷贝构造拷贝赋值移动构造移动赋值析构四、示例全部显式声明/禁用classDemo{public:// 1. 默认构造Demo()default;// 2. 拷贝构造Demo(constDemo)delete;// 3. 拷贝赋值Demooperator(constDemo)delete;// 4. 移动构造Demo(Demo)default;// 5. 移动赋值Demooperator(Demo)default;// 6. 析构~Demo()default;};五、补充不自动生成的常用运算符容易混淆下面这些不会由编译器默认生成必须手动重载operator、operator-算术运算符operator、operator比较运算符operator[]、operator()、operator*流运算符 / 只有上面6个特殊成员函数是编译器按需隐式生成。另外四个一、先说结论编译器会隐式生成两个取地址重载但它们不属于「六大特殊成员函数」平时讲默认生成的特殊函数一般不提普通取地址T* operator()const取地址const T* operator() const1. 自动生成规则只要你没有手动重载operator编译器就会自动生成这两个版本structA{intx;};// 编译器隐式生成等价代码A*operator(){returnthis;}constA*operator()const{returnthis;}作用直接返回当前对象this指针。使用示例A a;A*pa;// 调用 operator()constA ca{};constA*cpca;// 调用 const 版本2. 为什么平时讲默认函数很少提它1标准定义区分两类成员C标准里把成员函数分成两类特殊成员函数special member functions默认构造、拷贝构造、拷贝赋值、析构、移动构造、移动赋值共6个这一组有严格的生成/抑制规则三/五法则只针对它们。内置运算符成员如 operatoroperator、operator-、operator[]等不属于特殊成员只要不手动写就自动生成不受三/五法则影响。2几乎没人重载operator正常业务代码完全不需要改写取地址只有少数黑魔法库智能指针代理、侵入式容器、调试追踪内存才会手动重载operator属于非常规操作。3. 手动重载后编译器不再生成默认版本一旦自己写任意一个operator编译器就不会再生成默认的两个版本structA{// 手动重载取地址编译器不再生成默认的 int*operator(){returnx;}intx;};A a;A;// 调用自定义版本返回 int*不再返回 A*constA ca{};ca;// 编译报错没有 const 版 operator4. 补充还有两个配套默认生成的一元运算符除了operator编译器还会隐式生成operator-箭头只有类是智能指针/包装器风格才会用到普通类不会触发使用operator*解引用同样极少重载总结对比六大特殊成员函数考试/面试必考默认构造、拷贝构造、拷贝赋值、析构、移动构造、移动赋值受三/五法则约束。默认生成但不属于特殊成员operator()/operator() const不受三/五法则约束教材一般不列入“默认生成函数”清单。面试如果问“C 类编译器默认生成哪些成员函数”优先答6个特殊成员如果面试官追问有没有其他默认生成的运算符再补充取地址重载。