为什么删除没有虚拟 dtor 的 class 是可以的,如果它继承了带有虚拟 dtor 的 class

Why delete a class without virtual dtor is OK if it inherits a class with virtual dtor

考虑下面的代码

#include <cstdio>
#include <memory>

struct Base1
{
    Base1() = default;
    virtual ~Base1() = default;
    //~Base1() = default;
};

struct Base2 : public Base1
{
    Base2()
    {
        printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
    }
    ~Base2() // non-virtual destructor
    {
        printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
    }
};

struct Derive : public Base2
{
    Derive()
    {
        printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
    }
    ~Derive()
    {
        printf("%s:%d:%s\n", __FILE__, __LINE__, __func__);
    }
};

int main()
{
    std::unique_ptr<Base2> d = std::make_unique<Derive>();
    return 0;
}

classBase2没有虚析构函数,但是继承了Base1有虚析构函数

代码 std::unique_ptr<Base2> d = std::make_unique<Derive>(); 正在尝试删除类型为 Derive 的对象上的 Base2,我原以为只会调用 Base2 的 dtor,但不会调用Derive.

但实际上它工作正常:

main.cpp:15:Base2
main.cpp:27:Derive
main.cpp:31:~Derive
main.cpp:19:~Base2

所以看起来只要"real"基础class(这里是Base1)有虚拟dtor,所有继承的class都不需要有虚拟dtor,是吗? 如果有,请问哪里可以找到相关的文档?

因为如果它继承自一个带有虚析构函数的class,那么它就有一个虚析构函数,即使你不必明确地将它标记为virtual

~Base2() // actually a virtual destructor

注意,如果你想确保~Base2()是独立于~Base1()的虚拟,那么你应该将它标记为virtual。但通常你想要做的是确保 Base1() 实际上是虚拟的。这可以通过使用 override 说明符来实现:

~Base2() override; // fail to compile if ~Base1() is not virtual

是的,如果 class 有一个基础 class,其 destructor 被声明为 virtual,它的析构函数也将是 virtual;无论是否明确声明为 virtual

Even though destructors are not inherited, if a base class declares its destructor virtual, the derived destructor always overrides it. This makes it possible to delete dynamically allocated objects of polymorphic type through pointers to base.

class Base {
 public:
    virtual ~Base() { /* releases Base's resources */ }
};

class Derived : public Base {
    ~Derived() { /* releases Derived's resources */ }
};

int main()
{
    Base* b = new Derived;
    delete b; // Makes a virtual function call to Base::~Base()
              // since it is virtual, it calls Derived::~Derived() which can
              // release resources of the derived class, and then calls
              // Base::~Base() following the usual order of destruction
}

根据标准,[class.dtor]/13

(强调我的)

A prospective destructor can be declared virtual ([class.virtual]) or pure virtual ([class.abstract]). If the destructor of a class is virtual and any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.