纯虚析构函数必须在类外定义实现;声明为virtual ~classname() = 0; 使类成为抽象类,但链接时需实际函数地址,故必须提供类外定义(无virtual、无=0、有函数体),否则报undefined reference。

纯虚析构函数必须在类外定义实现
纯虚析构函数 virtual ~ClassName() = 0; 的语法允许类成为抽象类,但它和其它纯虚函数不同:**它必须有定义体**,否则链接会失败。因为派生类的析构函数在调用时,会隐式调用基类析构函数(包括纯虚的那个),而链接器需要实际的函数地址。
类外实现写法:函数名前不加 virtual,也不带 = 0
在类声明中写成纯虚,但在类外定义时,就是普通函数定义——去掉 virtual 和 = 0,且必须提供函数体(哪怕为空)。
常见错误是忘记定义,或误写成 virtual ~Base() = 0 {}(语法错误)或 ~Base() = 0;(没定义,链接时报 undefined reference to 'Base::~Base()')。
正确做法:
class Base {
public:
virtual ~Base() = 0; // 声明为纯虚
};
Base::~Base() {} // 类外定义:无 virtual,无 = 0,有函数体
为什么不能只声明不定义?
析构函数调用链是自动、强制的:即使派生类析构函数为空,编译器仍会插入对基类析构函数的调用。若基类纯虚析构没定义,链接阶段找不到符号,报错类似:
undefined reference to 'Base::~Base()'
注意:这个错误通常出现在使用 Base* 指向派生对象并 delete 时,而非单纯编译类定义。
- 纯虚析构函数 ≠ 可以不实现 —— 它是唯一必须定义的纯虚函数
- 定义可以为空(
{}),但不能省略 - 如果基类有资源需清理,就在这里写释放逻辑(和普通析构一样)
和普通虚析构函数相比有什么影响?
语义上,virtual ~Base() = 0; 表示「该类不可实例化」,比 virtual ~Base() {} 更严格;行为上完全一致——都支持多态析构,都要求派生类析构被正确调用。
性能、ABI、内联等均无差异。唯一的实操区别就是:前者强制你多写一行类外定义。
容易忽略的一点:如果头文件里只声明了纯虚析构但忘了在 .cpp 里定义,而多个源文件都包含该头文件并触发了 delete Base*,链接错误可能显得“飘忽不定”——不是每次构建都暴露,取决于模板实例化或内联优化是否绕过了调用点。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











