☰
基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的
2026/10/5 2:56:10 网站建设 项目流程

polymorph源代码:

#include<iostream>// /*structBase{virtualvoidf(){}};structDerived:Base{voidf()override{}};intmain(){Base*p=newDerived;return0;}// */

C++ 基类指针删除派生类对象:为什么需要虚析构函数

polymorph.cpp当前启用的代码是:

Base*p=newDerived;

目前没有delete p;,所以这里是内存没有释放。如果加上delete p;,确实会产生未定义行为。

关键在于:指针类型是Base*,但它指向的完整对象是Derived。

Base*p=newDerived;// ↑ ↑// 静态类型 动态类型

delete p;需要完成两个步骤:

  1. 析构对象,清理对象管理的资源。
  2. 释放new分配的内存。

为了正确销毁这个Derived对象,需要先执行Derived的析构函数,再执行Base的析构函数。虚析构函数提供了通过基类指针找到实际对象析构函数的机制。

你的Base只有:

virtualvoidf(){}

这只保证p->f()能调用Derived::f()。每个函数是否为虚函数是分别决定的,f()是虚函数不会让析构函数自动变成虚函数。

编译器隐式生成的Base::~Base()仍然是非虚的。

没有虚析构时,通常会按指针的静态类型选择Base::~Base(),
无法通过这条析构调用完成派生对象的清理。

更复杂的继承结构还可能涉及基类子对象与完整对象的地址不同、释放内存时需要正确的对象大小等问题。

因此,C++ 对这里的普通单对象delete明确规定:通过基类指针删除派生类对象,基类必须具有虚析构函数,否则行为未定义。

要注意,“只调用基类析构函数”只是常见表现,不是标准保证的结果。即使你这里的Derived没有数据成员、没有资源要释放,程序运行起来也正常,仍然违反这条规则。

修改为:

structBase{virtualvoidf(){}virtual~Base()=default;};

之后:

Base*p=newDerived;deletep;// 正确:~Derived() → ~Base() → 释放内存

Derived的析构函数会自动成为虚函数,无须显式声明。

文件中注释掉的std::unique_ptr<Base>版本也有同样的问题:它的默认删除器最终执行的仍然是对Base*的delete,因此也需要给Base添加虚析构函数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询