【问题标题】:virtual destrutors vs normal methods in C++C ++中的虚拟析构函数与普通方法
【发布时间】:2018-10-24 09:24:00
【问题描述】:

考虑以下三个 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)

我想知道为什么我不能在类定义之外定义虚拟析构函数,但是我可以在类定义中做到这一点。此外,我可以在类之外定义方法,但不能定义析构函数。

【问题讨论】:

  • 这在我看来不像 JavaScript 吗? C++ 标签会更适合这个问题
  • 抱歉,我忘了从我问的上一个问题中更改它。还要感谢构造函数与析构函数的捕获。但是这个问题仍然有效
  • 这些代码示例都没有实际编译(或提供您发布的链接器错误)。请提供真实的minimal reproducible examples,不要随意发明代码
  • virtual ~base() =0; pure virtual virtual ~base() {} virtual virtual ~base() =0 {}; pure virtual with impl
  • 必须定义一个纯虚析构函数,并且由于语法问题,它只能在类定义之外完成。

标签: c++ destructor virtual-functions virtual-destructor


【解决方案1】:

这是错误的

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

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

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

base::~base() {}

我想知道为什么我无法在类定义之外定义虚拟析构函数

好吧,你可以:我刚刚做到了。


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

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

【讨论】:

  • 纯虚析构函数声明没有错。你的措辞是错误的。
  • 好的,我在代码中添加了 base::~base(){} 并且它可以工作。不过我很困惑,因为我认为您不需要实现虚函数,而且在您执行此操作时似乎您正在实现它
  • @MaximEgorushkin 关心扩展吗?我不明白。
  • 换个说法,为什么后两个程序不需要 base::~base(){}
  • 那为什么在后两种情况下编译运行良好?
【解决方案2】:

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

如果您将 case 2 derived d; 放在主体中,您将得到与 case 1 相同的错误,因为链接器必须创建派生的成员函数定义并且需要 ~base() 主体,以防万一1.

【讨论】:

    猜你喜欢
    • 2017-08-13
    • 2011-08-12
    • 1970-01-01
    • 2012-09-21
    • 2012-04-18
    • 2016-01-22
    • 2010-10-24
    • 2017-05-31
    • 2016-08-14
    相关资源
    最近更新 更多