多态中的虚拟析构函数 类

Virtual destructor in polymorphic classes

我知道只要你有一个多态基 class,基 class 就应该定义一个虚拟析构函数。这样当一个指向derived-class对象的base-class指针被删除时,它会先调用derivedclass的析构函数。如果我在这里错了,请纠正我。

此外,如果 base-class 析构函数是非虚拟的,则删除指向派生对象的 baseclass 指针将是未定义的行为。如果我也错了,请纠正我。

所以我的问题是:为什么当 base-class 析构函数是非虚函数时,对象不会被正确销毁?

我假设这是因为虚函数有某种 table ,每当调用虚函数时都会记住和查询。并且编译器知道当一个对象应该被删除时,它应该首先调用派生的析构函数。

我的假设正确吗?

如果在删除对象时变量的静态类型是bas类型,则将调用基类型的析构函数,但子class的析构函数不会被调用(因为它不是虚拟的)。

因此baseclass分配的资源会被释放,subclass分配的资源不会。

因此对象不会被正确销毁。

你说得对 table:它被称为虚拟方法 table 或 "vtable"。但是析构函数非虚的结果并不是析构函数没有按正确的顺序调用,而是子class(es)的析构函数根本没有被调用!

考虑

struct Base {
    void f() { printf("Base::f"); }
};
struct Derived : Base {
    void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();

这会打印 Base::f,因为 Base::f 不是虚拟的。现在对析构函数做同样的事情:

struct Base {
    ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
    ~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();

这会打印 Base::~Base。现在,如果我们将析构函数设为虚函数,那么与任何其他虚函数一样,将调用对象动态类型中的最终覆盖程序。析构函数覆盖基 class 中的虚拟析构函数(即使它的 "name" 不同):

struct Base {
    virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
    ~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();

调用 p->~Base() 实际上调用了 Derived::~Derived()。由于这是一个析构函数,在它的主体完成执行后,它会自动调用基类和成员的析构函数。所以输出是

Derived::~Derived
Base::~Base

现在,delete-expression 通常等同于先调用析构函数再调用内存释放函数。在这种特殊情况下,表达式

delete p;

相当于

p->~Base();
::operator delete(p);

因此,如果析构函数是虚拟的,则这样做是正确的:它首先调用 Derived::~Derived,然后在完成后自动调用 Base::~Base。如果析构函数不是虚拟的,可能的结果是只调用 Base::~Base