有虚函数的类析构函数不会自动变虚,必须显式声明virtual ~base(),否则通过基类指针delete派生类对象时析构函数不执行,导致资源泄漏。

基类有其他虚函数,析构函数不会自动变虚
不会。C++标准明确要求:即使类中已声明多个虚函数,~ClassName() 仍默认是非虚的。编译器不会因为存在 virtual void foo() 就给析构函数加 virtual 关键字。
常见错误现象是:写了虚函数但忘了加虚析构,结果用 Base* ptr = new Derived(); delete ptr; 时,~Derived() 根本不执行,导致 new 出来的资源(如 int*、文件句柄)泄漏。
- 虚函数表(vtable)里不会自动包含析构函数入口,除非你显式声明
virtual ~Base() - 派生类的析构函数是否为虚,只取决于基类析构函数是否为虚——这是“虚性继承”,不是“自动推导”
- 有虚函数的类通常意味着它会被多态使用,这时没加虚析构几乎等于埋雷
为什么编译器不自动补上虚析构
因为虚函数有运行时开销:每个对象多一个 vptr 指针,且虚调用无法内联。C++ 奉行“你不用,我就不给”,默认析构函数是平凡的(trivial),零成本。
如果编译器擅自把析构函数变虚,哪怕你只用栈对象(Derived d;),也会强制引入虚表,违背“零开销抽象”原则。
- 仅当类设计为多态基类(即预期被
new+ 基类指针管理)时,才需要虚析构 - 纯接口类(如只有纯虚函数)必须显式写
virtual ~Interface() = 0;并提供定义,否则链接失败 - 若基类完全不打算被继承(
final类),或只用于栈对象,虚析构反而浪费空间
怎么快速检查和修复
看类有没有虚函数?有 → 立刻检查析构函数是否带 virtual。没有?那基本不用操心;有但没加?马上补。
- Clang/GCC 加
-Wdelete-non-virtual-dtor警告:删除非虚析构基类指针时触发 - 静态分析工具(如 clang-tidy)规则
cppcoreguidelines-special-member-functions会提示缺失虚析构 - 示例修复:
class Base { public: virtual ~Base() = default; };(C++11 起可用= default,语义等价于空实现)
纯虚析构函数必须写函数体
如果写成 virtual ~Base() = 0;,类变成抽象类,但链接阶段会报错:undefined reference to 'Base::~Base()'。
原因:派生类析构时,**一定会隐式调用基类析构函数**,哪怕它是纯虚的。所以必须提供定义:
class AbstractBase {
public:
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {} // 必须写,哪怕为空
这点容易被忽略——纯虚 ≠ 可以不实现,析构函数的调用链是硬性的,编译器不给你绕过基类清理的机会。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











