C++ - 虚析构和纯虚析构的作用
在C++中,虚析构函数和纯虚析构函数的作用与多态性和资源管理密切相关。以下是它们的详细说明:
一、虚析构函数的作用
1. 核心问题
当通过基类指针删除一个派生类对象时,如果基类的析构函数不是虚函数,则只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类中分配的资源(如内存、句柄等)未被释放,引发内存泄漏或资源泄漏。
例如:
#include <iostream>
using namespace std;
class Base {
public:
Base() { std::cout << "Base 构造函数\n"; }
~Base() { std::cout << "Base 析构函数\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived 构造函数\n"; }
~Derived() { std::cout << "Derived 析构函数\n"; }
};
int main()
{
Base* obj = new Derived();
delete obj;//通过基类指针删除一个派生类对象
return 0;
}
运行结果:

可以看到 Derived的析构函数 并未调用,会导致内存泄露问题。
2. 解决方案
将基类的析构函数声明为虚函数:
class Base {
public:
virtual ~Base() {} // 虚析构函数
};
class Derived : public Base {
public:
~Derived() { /* 释放派生类资源 */ }
};
// 使用基类指针删除派生类对象
Base* obj = new Derived();
delete obj; // 正确调用 Derived::~Derived() 和 Base::~Base()
3. 关键点
-
多态销毁:虚析构函数确保通过基类指针删除对象时,调用完整的析构链(派生类 → 基类)。
-
设计准则:如果类可能被继承,且需要通过基类指针操作对象,析构函数必须为虚函数。
-
性能影响:虚函数会引入虚表(vtable)开销,但现代编译器优化后影响极小。
二、纯虚析构函数的作用
1. 核心问题
如何定义一个抽象基类,但该类没有其他需要强制子类实现的纯虚函数?
2. 解决方案
将析构函数声明为纯虚函数,同时提供其实现:
class AbstractBase {
public:
virtual ~AbstractBase() = 0; // 纯虚析构函数
};
AbstractBase::~AbstractBase() { /* 基类析构实现 */ }
class Concrete : public AbstractBase {
public:
~Concrete() { /* 派生类析构实现 */ }
};
3. 关键点
-
抽象类约束:纯虚析构函数使类成为抽象类,无法直接实例化。
-
必须提供实现:纯虚析构函数需要单独定义,因为派生类析构时会隐式调用基类析构函数。
-
替代方案:若类已有其他纯虚函数,无需使用纯虚析构函数来标记抽象类。
三、对比与总结
| 特性 | 虚析构函数 | 纯虚析构函数 |
|---|---|---|
| 语法 | virtual ~Base() {} |
virtual ~Base() = 0; + 类外定义 |
| 目的 | 确保多态对象的完整析构 | 定义抽象类,强制派生类实现析构逻辑 |
| 是否可实例化基类 | 是 | 否(抽象类) |
| 必须提供实现 | 否(可默认生成) | 是(否则链接错误) |
| 典型使用场景 | 基类可能被继承并通过指针删除对象 | 基类需为抽象类且无其他纯虚函数 |
四、代码示例
1. 虚析构函数
#include <iostream>
using namespace std;
class Base {
public:
Base() { std::cout << "Base 构造函数\n"; }
virtual ~Base() { std::cout << "Base 析构函数\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived 构造函数\n"; }
~Derived() { std::cout << "Derived 析构函数\n"; }
};
int main()
{
Base* obj = new Derived();
delete obj;
return 0;
}
运行结果:

2. 纯虚析构函数
#include <iostream>
using namespace std;
class AbstractBase
{
public:
AbstractBase() { std::cout << "AbstractBase 构造函数\n"; }
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() { std::cout << "AbstractBase 纯虚析构函数\n"; }
class Concrete : public AbstractBase {
public:
Concrete() { std::cout << "Concrete 构造函数\n"; }
~Concrete() { std::cout << "Concrete 析构函数\n"; }
};
int main()
{
AbstractBase* obj = new Concrete();
delete obj;
return 0;
}
运行结果:

五、总结
-
虚析构函数:用于多态场景,确保派生类资源正确释放。
-
纯虚析构函数:用于定义抽象基类,强制派生类实现析构逻辑,同时自身需提供实现。
-
核心原则:若类可能被多态使用,基类必须提供虚析构函数;若需抽象类但无其他纯虚函数,可用纯虚析构函数。

浙公网安备 33010602011771号