具有虚拟析构函数的基类子类中的默认析构函数

Posted

技术标签:

【中文标题】具有虚拟析构函数的基类子类中的默认析构函数【英文标题】:Default destructor in subclasses of base class with a virtual destructor 【发布时间】:2018-06-29 14:10:51 【问题描述】:

我有一个带有虚拟析构函数的基类AA 的后代 BC 使用默认析构函数。通过指向A的指针删除C的对象是否安全?

更具体地说,请考虑以下示例代码:

class A 
 public:
      A();
      virtual ~A() /* code here */;
 ;
 class B: public A 
      B() /* code....*/;
      /* NO DESTRUCTOR SPECIFIED */
   ;
 class C: public B /*same as above, no destructor */;
 class D: public B /* same as above, no destructor*/

要运行的代码如下所示:

A* getAPointer(void); /* a function returning a C or a D*/
A* aptr=getAPointer();
/* aptr is declared as A*, but points to either an object of class C 
  or class D*/
delete aptr;

delete aptr 安全吗?它做对了吗:如果aptr指向C类的对象,aptr首先调用C的析构函数,然后是B的析构函数,最后是A的析构函数?

【问题讨论】:

【参考方案1】:

是的,它是安全的。在派生类的析构函数中添加virtual 是多余的。

考虑该机制的工作原理。当使用delete 时,运行时需要知道销毁链应该从哪个析构函数开始。如果delete 操作数的静态类型有一个virtual 析构函数,那么运行时已经足够知道它必须采取额外的麻烦并检查动态类型。

在您的情况下,它发现动态类型是C,因此调用了C::~CC::~C 自动连接到 B::~B,而那个自动连接到 A::~A

要求C(或B)的析构函数为virtual 是没有意义的。毕竟,如果A::~Avirtual,那么运行时无论如何都必须找出动态的C 类型。此时,C::~C 是否为virtual 并不重要。会有什么不同?

【讨论】:

通过该描述,不明显的是,如果您将指针声明为“中间”类型 B,并且实际的具体运行时类型是 C,它也可以正常工作。AFAIK,派生类不能“去虚拟化”基类中虚拟的东西。【参考方案2】:

通过指向 A 的指针删除 C 的对象是否安全?

是的,这是完全安全的,因为类 BCD 中的所有析构函数都是隐式虚拟的。

发件人:

15.4 析构函数 [class.dtor]

10 析构函数可以声明为虚拟(13.3)或纯虚拟(13.4); 如果该类或任何派生类的任何对象是在 程序,应定义析构函数。 如果一个类有一个基类 使用虚拟析构函数,其析构函数(无论是用户还是 隐式声明)是虚拟的。

由于A 有一个虚拟析构函数,那么BCD 分别有一个虚拟析构函数并且:

delete aptr;

工作正常。

【讨论】:

【参考方案3】:

通过指向A的指针删除C的对象是否安全?

是的。由于A 的析构函数是virtualC 的析构函数将被调用。这仅仅是由于 动态调度 的工作原理。

【讨论】:

以上是关于具有虚拟析构函数的基类子类中的默认析构函数的主要内容,如果未能解决你的问题,请参考以下文章

NO.6: 为多态基类声明virtual析构函数

为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数

虚拟析构函数是继承的吗?

基本语言

C++ 中的虚拟默认析构函数

删除指向子类的指针会调用基类析构函数吗?