为什么纯虚拟析构函数需要实现

Why a pure virtual destructor needs an implementation

本文关键字:实现 析构函数 虚拟 为什么      更新时间:2023-10-16

我知道需要纯虚拟析构函数的情况。我也知道,如果我们不为它们提供实现,它会给我一个链接器错误。我不明白的是为什么在代码片段中会出现这种情况,如下所示:

int main()
{
    Base * p = new Derived;
}

这里没有删除,所以没有调用析构函数,所以不需要它的实现(假设它的行为应该像其他已声明但未定义的正常函数一样,链接器仅在我们调用它们时才抱怨)......还是我错过了什么?

我需要了解为什么这应该是一个特例?

编辑:基于BoBTFish的评论

这是我的基类和派生类

class Base
{
public:
    Base(){}
    virtual ~Base() = 0;
};
class Derived : public Base
{
};

编译器尝试在给定virtual(纯或非纯)析构函数的情况下构建虚拟表,并且由于找不到实现而抱怨。

virtual析构函数与其他virtual函数不同,因为它们是在销毁对象时调用的,无论它是否已实现。这要求编译器将其添加到 vf 表中,即使它未显式调用,因为派生类析构函数需要它。

从学究上讲,该标准要求实现纯virtual析构函数。

C++11 标准:

12.4 析构函数

第9段:

析构函数可以声明为虚拟 (10.3) 或纯虚拟 (10.4);如果该类的任何对象或任何派生类是在程序中创建的,应定义析构函数。如果类具有具有虚拟析构函数,其析构函数(无论是用户声明还是隐式声明)是虚拟的。

构函数在这一点上与其他虚函数不同,因为它们是特殊的,并且在基中自动调用,没有可能、有用或有意义的方法来防止它。

[C++11: 12.4/9]:析构函数可以声明为virtual(10.3)或纯virtual(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。如果类具有具有虚拟析构函数的基类,则其析构函数(无论是用户声明还是隐式声明)都是虚拟的。

碱基

总是被销毁的,为此,需要一个碱基析构函数定义。相反,其他被覆盖的虚拟函数根本不会自动调用。因此,特殊情况要求。

struct Base
{
   virtual ~Base()    = 0;  // invoked no matter what
   virtual void foo() = 0;  // only invoked if `Base::foo()` is called
};
Base::~Base() {}
/* void Base::foo() {} */
struct Derived : Base
{
   virtual void foo() { /* Base::foo(); */ }
};
int main()
{
    std::unique_ptr<Base> ptr(new Derived());
}

一个实际的原因是析构函数在几乎所有实现的 vtable 中的虚拟成员函数列表中都排在第一位。实现倾向于在定义第一个虚拟成员函数时定义 vtable 本身。所以,没有析构函数,没有vtable。而 vtable 至关重要。