构造函数必须与类名完全一致且无返回类型;初始化列表优于函数体内赋值,尤其对const、引用及无默认构造函数的成员;析构函数在对象销毁时自动调用,负责资源清理,基类需声明virtual;移动与拷贝构造需显式控制;析构中虚函数调用不具多态性。

构造函数怎么写才不会出错
构造函数不是随便起个名字就行的,它必须和类名完全一致,且不能有返回类型(连 void 都不能写)。常见错误是手滑写成 void MyClass() 或 MyClass constructor(),编译器会直接当普通函数处理,对象创建时根本不会调用。
初始化列表比在函数体内赋值更安全、更高效,尤其对 const 成员、引用成员或没有默认构造函数的类成员来说,这是唯一合法的初始化方式。
- 用初始化列表:
MyClass(int x) : m_x(x), m_ref(other_var) {} - 别在函数体里赋值:
MyClass(int x) { m_x = x; }(对const int m_x;会编译失败) - 多个参数时注意顺序:初始化列表顺序按成员声明顺序执行,和列表中写的顺序无关
析构函数什么时候被调用
析构函数在对象生命周期结束时自动调用,比如局部对象离开作用域、delete 堆上对象、容器销毁元素。它不负责释放内存本身(那是 operator delete 的事),而是负责清理资源:关文件、释放 new 出来的内存、解除锁、注销回调等。
一个典型坑是:如果类里有裸指针成员并手动管理内存,但析构函数没写或写错了,就会导致内存泄漏或重复释放。
立即学习“C++免费学习笔记(深入)”;
- 必须声明为
virtual的情况:类可能作为基类被继承,且你打算用基类指针删除派生类对象(否则只会调用基类析构,派生类部分资源不释放) - 空析构函数也建议显式写出来:
~MyClass() = default;或~MyClass() {},避免隐式生成带来意外行为 - 不要在析构函数里抛异常——C++ 标准规定,若栈展开期间析构函数再抛异常,程序直接终止
移动构造函数和拷贝构造函数冲突怎么办
当你写了自定义拷贝构造函数(MyClass(const MyClass&)),编译器就不会自动生成移动构造函数(MyClass(MyClass&&))。这时候如果代码里出现临时对象或 std::move,可能意外触发拷贝而非移动,性能掉一截。
解决办法不是“删掉拷贝构造”,而是显式控制:要么用 = default 补全移动操作,要么用 = delete 禁用不需要的操作。
- 想支持移动:加上
MyClass(MyClass&&) = default; - 想禁用拷贝:声明
MyClass(const MyClass&) = delete; - 注意:如果类里有
std::mutex这类不可拷贝不可移动成员,整个类默认就既不可拷贝也不可移动
析构函数里能调用虚函数吗
能写,但结果往往不是你想要的——在析构过程中,虚函数表指针会逐步回退到父类状态,最终调用的是当前正在析构的那个类的版本,而不是最派生类的重写版本。这和构造过程类似,都是“半成品”状态。
所以别指望在析构函数里靠虚函数做多态清理;如果真需要动态行为,得提前保存状态,或用其他机制(如策略对象、回调注册)绕开。
- 示例:派生类重写了
cleanup(),但在基类析构函数里调用cleanup(),实际执行的是基类版本 - 更安全的做法:把需要多态的行为拆到单独的
close()或shutdown()方法中,由用户显式调用 - 析构函数只做确定性、与类型强绑定的收尾,比如
fclose(m_fp)、delete m_buf










