如果删除不带虚拟dtor的类,为什么可以删除,如果它继承了带虚拟dtor的类

Min*_*ine 3 c++ virtual destructor

考虑下面的代码

#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;
}
Run Code Online (Sandbox Code Playgroud)

该类Base2没有虚拟析构函数,但它继承Base1了具有虚拟析构函数的类。

代码std::unique_ptr<Base2> d = std::make_unique<Derive>();正在尝试删除Base2类型为的对象Derive,我期望只Base2调用的dtor,而不是for Derive

但实际上它可以正常工作:

main.cpp:15:Base2
main.cpp:27:Derive
main.cpp:31:~Derive
main.cpp:19:~Base2
Run Code Online (Sandbox Code Playgroud)

因此,看起来只要“真正的”基类(这里是Base1)具有虚拟dtor,就不需要所有继承的类都具有虚拟dtor,对吗?如果是,我在哪里可以找到相关文件?

jua*_*nza 6

因为如果它继承自具有虚拟析构函数的类,那么它就具有虚拟析构函数,即使您不必显式将其标记为virtual

~Base2() // actually a virtual destructor
Run Code Online (Sandbox Code Playgroud)

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

~Base2() override; // fail to compile if ~Base1() is not virtual
Run Code Online (Sandbox Code Playgroud)


son*_*yao 6

是的,如果一个类的基类的析构函数被声明为virtual,则其析构函数也将为virtual;不论是否virtual明确声明。

即使没有继承析构函数,但如果基类将其析构函数声明为虚拟的,则派生的析构函数始终会覆盖它。这样就可以通过指向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
}
Run Code Online (Sandbox Code Playgroud)

根据标准[class.dtor] / 13

(强调我的)

可以将预期的析构函数声明为虚拟([class.virtual])或纯虚拟([class.abstract])。如果一个类的析构函数是虚拟的,并且在程序中创建了该类或任何派生类的任何对象,则应定义该析构函数。如果一个类具有带有虚拟析构函数的基类,则其析构函数(无论是用户声明的还是隐式声明的)都是virtual