【问题标题】:Implicitly declared destructor隐式声明的析构函数
【发布时间】:2021-11-20 08:26:52
【问题描述】:

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

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

现在,考虑这个例子:

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

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

【问题讨论】:

    标签: c++11 inheritance virtual destructor


    【解决方案1】:

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

    不,根据class.dtor/3

    类 X 的隐式声明的预期析构函数将具有 表格

    ~X()
    

    当然,根据class.dtor/12

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


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

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

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

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

    [...]

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

    [...]

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

    执法

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

    【讨论】:

    • @mfnx 通过指向 C++ 核心指南的链接查看更新的答案。但一般来说:如果你的类打算用于多态(例如声明至少一个虚函数),那么你绝对应该遵守这个建议,但对于继承仅用于实现继承(无多态)的类仅为 dtor 添加 vtable 可能会被视为浪费。
    猜你喜欢
    • 2016-12-28
    • 2020-01-21
    • 2021-12-18
    • 2012-07-19
    • 2021-01-20
    • 1970-01-01
    • 2016-01-02
    • 2014-06-28
    相关资源
    最近更新 更多