C++ 中的虚拟析构函数与普通方法

virtual destrutors vs normal methods in C++

考虑以下三个 C++ 程序:

节目 1

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived();
};

derived::~derived(){}

int main(){}

节目 2

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived(){}
};

int main(){}

节目 3

struct base{
  virtual void func() =0;
};

struct derived: public base{
  void func();
};

void derived::func(){}

int main(){}

程序 #2 和 #3 编译并且 运行 很好,但是第一个给出以下错误:

Undefined symbols for architecture x86_64:
  "base::~base()", referenced from:
    derived::~derived() in main-d923b9.o
ls: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我想知道为什么我无法在 class 定义之外定义虚拟析构函数,但我可以在 class 定义内定义。此外,我可以在 class 之外定义方法,但不能定义析构函数。

这是错误的

struct base{
  virtual ~base() =0;
};

因为base::~base没有定义。即使它已被声明为纯虚函数,也需要对其进行定义(在 class 之外,没有语法方法可以将函数声明为纯虚函数并将其内联定义)因此 derived 可以从中继承:

struct base
{
    virtual ~base() = 0;
};

base::~base() {}

I'd like to know why I am unable to define virtual destructors outside of the class definition

嗯,你可以:我刚刚做到了。


那么,为什么你需要实现一个已经被声明为纯虚拟的函数(~base)?

由于derived继承自base,当derived类型的对象被析构时,它必然会调用base的析构函数。这就是继承的工作方式。从某种意义上说,derived::~derived 需要 link 和 base::~base。尽管 base::~base 是一个纯虚拟(意味着从 base 继承的 class 不是完整类型,除非它定义了析构函数)它 需要 被定义以便 ~derived 找到它并且 link 他们变得快乐。

为什么要构建程序 2,答案在于 link 的工作原理。当函数定义在 class 声明之外时,linker 需要在最终的二进制文件中创建函数体,因此它也需要有 ~base() 定义。

如果你在主体中放入案例 2 derived d;,你将得到与案例 1 相同的错误,因为 linker 将必须创建派生成员函数定义并将需要 ~base() 主体,如案例 1.