具有虚拟析构函数的基类子类中的默认析构函数
Posted
技术标签:
【中文标题】具有虚拟析构函数的基类子类中的默认析构函数【英文标题】:Default destructor in subclasses of base class with a virtual destructor 【发布时间】:2018-06-29 14:10:51 【问题描述】:我有一个带有虚拟析构函数的基类A
。 A
的后代 B
和 C
使用默认析构函数。通过指向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::~C
。 C::~C
自动连接到 B::~B
,而那个自动连接到 A::~A
。
要求C
(或B
)的析构函数为virtual
是没有意义的。毕竟,如果A::~A
是virtual
,那么运行时无论如何都必须找出动态的C
类型。此时,C::~C
是否为virtual
并不重要。会有什么不同?
【讨论】:
通过该描述,不明显的是,如果您将指针声明为“中间”类型 B,并且实际的具体运行时类型是 C,它也可以正常工作。AFAIK,派生类不能“去虚拟化”基类中虚拟的东西。【参考方案2】:通过指向 A 的指针删除 C 的对象是否安全?
是的,这是完全安全的,因为类 B
、C
和 D
中的所有析构函数都是隐式虚拟的。
发件人:
15.4 析构函数 [class.dtor]
10 析构函数可以声明为虚拟(13.3)或纯虚拟(13.4); 如果该类或任何派生类的任何对象是在 程序,应定义析构函数。 如果一个类有一个基类 使用虚拟析构函数,其析构函数(无论是用户还是 隐式声明)是虚拟的。
由于A
有一个虚拟析构函数,那么B
和C
、D
分别有一个虚拟析构函数并且:
delete aptr;
工作正常。
【讨论】:
【参考方案3】:通过指向
A
的指针删除C
的对象是否安全?
是的。由于A
的析构函数是virtual,C
的析构函数将被调用。这仅仅是由于 动态调度 的工作原理。
【讨论】:
以上是关于具有虚拟析构函数的基类子类中的默认析构函数的主要内容,如果未能解决你的问题,请参考以下文章