C++ 虚析构函数

2025年8月29日 | 阅读 7 分钟

在 C++ 中,虚析构函数用于在使用基类指针对象删除派生类实例时,释放派生类对象或实例分配的内存空间。基类或父类析构函数使用 virtual 关键字,确保基类和派生类析构函数都将在运行时被调用,但它会首先调用派生类,然后调用基类来释放两个析构函数占用的空间。

语法

它具有以下语法:

简单的虚析构函数示例

让我们看一个 C++ 中虚析构函数的示例。

示例

编译并运行

输出

Derived Destructor
Base Destructor

说明

在此示例中,ptr 是一个基类指针,用于指向 Derived 对象。Base 具有一个虚析构函数。当在 main() 函数中执行 delete ptr 时,将首先调用 Derived 类的析构函数,然后调用 Base 类的析构函数。它确保对象中派生部分和基部分的正确清理。

为什么我们在 C++ 中使用虚析构函数?

当类中的对象超出作用域或 main() 函数的执行即将结束时,程序会自动调用析构函数,以释放类析构函数占用的空间。当删除指向派生类的基类指针对象时,由于编译器的早期绑定,只调用父类析构函数。这样,它会跳过调用派生类的析构函数,从而导致程序中出现内存泄漏问题。

如果我们在基类中析构函数波浪号 (~) 符号前使用 virtual 关键字,它保证首先调用派生类的析构函数。之后,调用基类的析构函数,以释放继承类中两个析构函数占用的空间。

虚析构函数内部工作原理

在 C++ 中,编译器在创建虚函数类及其事件析构函数时生成虚表实体。类的所有对象都在其结构内部维护秘密虚表指针。

C++ 通过虚表访问执行运行时类型检查,以确定当析构函数具有 virtual 指定时需要执行哪些析构函数。

虚析构函数的使用

C++ 中虚析构函数有几种用法。其中一些如下:

1) 通过基指针进行多态删除

如果虚析构函数不可用,基类指针尝试删除派生类对象将只执行其基类析构函数。派生类的析构函数无法执行,从而导致资源泄漏。

C++ 通过基指针进行多态删除

让我们看一个示例来说明 C++ 中通过基指针进行多态删除。

示例

编译并运行

输出

Base Destructor

说明

在此示例中,基类未能包含虚析构函数声明。delete ptr 语句触发 Base 析构函数并跳过任何 Derived 析构函数的执行。之后,派生对象将遭受资源泄漏,因为这些对象无法释放动态内存或文件句柄。

2) 接口式基类

在 C++ 中,基类上的虚析构函数声明允许我们使用虚表在运行时正确执行析构函数序列。

示例

让我们看一个示例来说明 C++ 中的接口式基类。

示例

编译并运行

输出

Derived Destructor  
Base Destructor

说明

在此示例中,两个析构函数都以正确的顺序调用。之后,保证了完整的对象销毁。

3) 管理派生类中的动态资源

在 C++ 中,派生类分配内存或文件句柄等资源。如果基类中的析构函数不是虚函数,则如果以多态方式删除,它将永远不会被释放。

C++ 示例管理派生类中的动态资源

让我们看一个示例来说明如何在 C++ 中管理派生类中的动态资源。

示例

编译并运行

输出

Derived allocated memory  
Derived released memory  
Base cleaned up

说明

在此示例中,当在派生类中管理资源时,我们防止了内存泄漏。

C++ 示例,在不使用虚析构函数的情况下显示类析构函数

让我们看一个程序,在不使用 C++ 中的虚析构函数的情况下,显示类析构函数的不确定行为。

示例

编译并运行

输出

Constructor Base class
 Constructor Derived class
 Destructor Base class

说明

在此示例中,我们使用 Base* 指针创建 Derived 对象。我们还使用了基类。之后,它删除基类析构函数和派生类析构函数占用的指针对象。基类指针只删除基类的析构函数,而不调用程序中派生类的析构函数。因此,它会导致程序中的内存泄漏。

C++ 示例,使用虚析构函数显示类析构函数

让我们看一个程序,在 C++ 中使用虚析构函数显示类析构函数的行为。

示例

编译并运行

输出

Constructor Base class
 Constructor Derived class
 Destructor Derived class
 Destructor Base class

说明

在上面的程序中,我们在基类中使用了虚析构函数,它在调用基类析构函数之前调用派生类析构函数,并释放空间或解决程序中的内存泄漏问题。

结论

总之,C++ 中虚析构函数的实现允许在多态类继承设计中正确清理对象。通过虚析构函数,系统可以在使用基指针删除时执行基类和派生类析构函数。当缺少虚析构函数时,只有基析构函数会收到调用,这会将内存置于风险之中。

C++ 虚析构函数 MCQ

1) 在基类中将析构函数声明为虚函数的主要目的是什么?

  1. 通过此声明,析构函数可以进行函数重载。
  2. 支持构造函数继承
  3. 当基类指针删除对象时,派生类需要析构函数正确执行。
  4. 提高运行时性能
 

答案: c) 当基类指针删除对象时,派生类需要析构函数正确执行。


2) 我们什么时候应该将基类析构函数声明为虚函数?

  1. 如果类将通过多态性使用,则需要虚析构函数。
  2. 只有当类包含静态成员时,才需要虚析构函数。
  3. 对象在栈内存上创建。
  4. 存在一项规则,要求在没有成员的基类中强制使用虚析构函数。
 

答案: a) 如果类将通过多态性使用,则需要虚析构函数。


3) 为什么纯虚析构函数即使标记为 =0 也需要定义?

  1. C++ 语言不支持纯虚函数。
  2. 因为析构函数总是在对象销毁期间被调用。
  3. 编译器在操作中不识别 virtual 关键字。
  4. 基类对象实际上不存在。
 

答案: b) 因为析构函数总是在对象销毁期间被调用。


4) 析构函数中的 virtual 关键字确保了什么?

  1. 析构函数不能被覆盖。
  2. 派生类的对象是唯一能够访问析构函数的实体。
  3. 在删除期间,调用正确的派生类析构函数。
  4. 析构函数在运行时执行得更快。
 

答案: c) 在删除期间,调用正确的派生类析构函数。


5) 什么时候基类中的析构函数不需要是虚函数?

  1. 不包含析构函数的派生类将使用基类析构函数。
  2. 当基类从不以多态方式使用时。
  3. 类只包含公共数据成员。
  4. 当析构函数是默认的。
 

答案: b) 当基类从不以多态方式使用时。