首页 > 解决方案 > 隐式声明的析构函数

问题描述

如果我是正确的,默认的析构函数总是隐式声明的,除非用户声明它。根据cppreference

通过指向基类的指针删除对象会调用未定义的行为,除非基类中的析构函数是虚拟的

现在,考虑这个例子:

struct B {};
struct D : B {};

隐式声明的析构函数是B::~B()虚拟的吗?如果不是,我应该在使用继承时总是声明一个虚拟析构函数吗?

标签: c++11inheritancevirtualdestructor

解决方案


隐式声明的析构函数 B::~B() 是虚拟的吗?

不,根据class.dtor/3

类 X 的隐式声明的预期析构函数将具有以下形式

~X()

当然,根据class.dtor/12

如果一个类有一个带有虚拟析构函数的基类,那么它的析构函数(无论是用户声明的还是隐式声明的)都是虚拟的


如果不是,我应该在使用继承时总是声明一个虚拟析构函数吗?

C++ 核心指南,C.35建议将公共的基类析构函数设为虚拟:

C.35: 基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的

原因防止未定义的行为。如果析构函数是公共的,则调用代码可以尝试通过基类指针销毁派生类对象,如果基类的析构函数是非虚拟的,则结果未定义。如果析构函数是受保护的,那么调用代码就不能通过基类指针进行销毁,并且析构函数不需要是虚拟的;它确实需要受到保护,而不是私有,以便派生的析构函数可以调用它。通常,基类的编写者不知道销毁时要执行的适当操作。

[...]

注意虚函数定义了派生类的接口,无需查看派生类即可使用该接口。如果接口允许销毁,那么这样做应该是安全的。

[...]

例外我们可以想象一种情况,您可能需要一个受保护的虚拟析构函数:当一个派生类型的对象(并且只有这种类型)应该被允许通过指向基的指针来销毁另一个对象(而不是它自己)时。不过,我们在实践中还没有看到这样的案例。

执法

  • 具有任何虚函数的类应该有一个析构函数,该析构函数要么是公共的和虚拟的,要么是受保护的和非虚拟的。

推荐阅读