一个纯虚析构函数(Pure Virtual Destructor)。代码:
cpp
virtual ~Product() = 0; // 虚函数
这样写的目的:让 Product 成为一个抽象基类(不能实例化),同时又需要确保派生类对象被正确析构。
一、为什么析构函数要写成虚函数?
先回答“虚”的部分:
如果基类的析构函数不是虚函数,当通过基类指针删除派生类对象时,只会调用基类的析构函数,派生类的析构函数不会被调用,导致派生类资源泄漏。
cpp
Base *p = new Derived(); delete p; // 如果Base析构不是虚函数,Derived的析构不会被调用 ❌
所以基类析构函数必须声明为 virtual。
二、为什么写成 = 0(纯虚)?
= 0 让析构函数变成纯虚函数,效果是:
-
Product变成抽象类,不能创建对象:Product p;编译报错。 -
但仍然必须实现这个析构函数(没错,纯虚析构函数必须有函数体)。
三、纯虚析构函数的特殊规则
普通纯虚函数可以只有声明,没有实现(派生类必须重写)。
但析构函数不同:编译器在析构派生类对象时,最终会自动调用基类的析构函数。所以即使是纯虚析构函数,也必须提供实现。
正确的写法必须是:
cpp
// Product.h
class Product
{
public:
Product() {}
virtual ~Product() = 0; // 声明为纯虚
};
// Product.cpp
Product::~Product() {} // 👈 必须有函数体!
四、完整示例说明
cpp
#include <iostream>
using namespace std;
class Product {
public:
Product() { cout << "Product构造" << endl; }
virtual ~Product() = 0; // 纯虚析构
};
Product::~Product() { // 必须实现!
cout << "Product析构" << endl;
}
class Book : public Product {
public:
Book() { cout << "Book构造" << endl; }
~Book() { cout << "Book析构" << endl; }
};
int main() {
Product *p = new Book();
delete p; // 输出:Book析构 -> Product析构 ✅
return 0;
}
输出:
text
Product构造 Book构造 Book析构 Product析构
五、对比:其他写法
| 写法 | 是否抽象类 | 能否实例化 | 派生类析构是否安全 | 是否需要实现 |
|---|---|---|---|---|
~Product() {} | ❌ 否 | ✅ 能 | ✅ 安全(虚函数) | 需要 |
virtual ~Product() {} | ❌ 否 | ✅ 能 | ✅ 安全 | 需要 |
virtual ~Product() = 0; + 实现 | ✅ 是 | ❌ 不能 | ✅ 安全 | 必须实现 |
~Product() = 0;(无实现) | ✅ 是 | ❌ 不能 | ❌ 链接错误 | 缺实现会报错 |
六、什么时候这样写?
典型场景:你需要一个抽象基类定义接口(比如工厂模式中的 Product),同时这个基类需要做一些通用的清理工作,并且必须确保派生类的析构函数被正确调用。
cpp
// 工厂模式中的抽象产品
class Product {
public:
virtual void use() = 0; // 纯虚接口
virtual ~Product() = 0; // 保证派生类正确析构 + 抽象类
};
Product::~Product() {} // 基类清理逻辑
七、一句话总结
virtual ~Product() = 0;的意思:
让Product成为抽象类(不能实例化),同时确保通过基类指针删除派生类对象时,能正确调用派生类和基类的析构函数。
记住:纯虚析构函数必须在类外提供实现。
如果你看到的是 virtual ~Product() {}(没有 = 0),那它只是一个普通的虚析构函数,Product 可以实例化,不是抽象类。
&spm=1001.2101.3001.5002&articleId=162332286&d=1&t=3&u=02df2360d4384a0890b0754fb45b984d)
459

被折叠的 条评论
为什么被折叠?



