基类析构函数声明为纯虚函数(virtual ~Base() = 0;)可强制类为抽象类且禁止实例化,同时确保多态删除时正确调用派生类析构函数;但必须在类外提供定义(如Base::~Base() {}),否则链接失败。

为什么基类析构函数要声明为纯虚函数
当基类设计为抽象类、只供继承不许实例化,且子类有动态资源(如 new 出的内存)时,必须确保通过基类指针删除对象能调用到子类析构函数——这依赖虚析构函数。声明为纯虚(virtual ~Base() = 0;)可强制抽象性,但**仅声明不实现会导致链接错误**:即使没对象被直接销毁,C++ 标准仍要求虚表中该函数地址有效,而纯虚函数若未定义,链接器找不到符号。
如何正确定义纯虚析构函数
必须在类内声明为纯虚,在类外提供空实现(哪怕什么都不做)。这是 C++ 的特殊规则:纯虚函数可以有定义,且析构函数必须有定义。
常见错误现象:undefined reference to 'Base::~Base()'
正确写法:
class Base {
public:
virtual ~Base() = 0; // 声明为纯虚
};
Base::~Base() {} // 类外定义,哪怕为空
注意点:
-
= 0只能出现在类内声明处,类外定义时不能带= 0 - 定义可以是空函数体,也可以包含清理逻辑(如日志),但不能调用子类成员(此时子类已析构完毕)
- 如果基类已有其他纯虚函数,加这条纯虚析构不会改变其抽象性;如果没有,加它就使类变成抽象类
不写类外定义会出什么问题
编译可能通过,但链接阶段必然失败。原因不是“没用到”,而是 C++ 对象销毁时,即使是派生类对象,也会按继承链逐级调用所有基类析构函数——包括纯虚的那个。虚表需要该函数的真实地址。
典型报错(GCC/Clang):undefined reference to 'Base::~Base()'
容易踩的坑:
- 误以为“纯虚=不用实现”,在头文件里只写
virtual ~Base() = 0;就完事 - 在类内写成
virtual ~Base() = 0 {}—— 语法错误,C++ 不允许纯虚函数在类内定义 - 把实现写在头文件里但没加
inline,导致多文件包含时重复定义(应避免;推荐实现在 .cpp 中)
和普通虚析构函数比有什么区别
语义不同:普通虚析构(virtual ~Base() {})允许创建基类对象;纯虚析构(virtual ~Base() = 0; + 外部定义)强制类不可实例化,适合纯接口类。
性能无差异:两者都生成虚表条目,运行时开销一致。
兼容性注意:
- 子类析构函数自动为虚,无需显式写
virtual - 如果基类只有纯虚析构、没有其他纯虚函数,它仍是抽象类——这点常被忽略
- 析构函数的访问控制(如
protected)不影响纯虚性质,但会影响使用方式(比如禁止外部delete)
真正关键的不是“能不能写”,而是“链接器认不认”——只要声明了纯虚,就必须在某个翻译单元里给出定义,否则就是硬性链接失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











