虚拟攻击者与C ++中的常规方法

时间:2018-05-14 16:30:17

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

在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)

我想知道为什么我无法在类定义之外定义虚拟析构函数,但是我能够在类定义中完成它。另外,我可以在类外部定义方法,而不是析构函数。

2 个答案:

答案 0 :(得分:4)

这是错误的

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的类不是完整类型,除非它定义了析构函数),它需要来定义{{1}找到它并且链接器变得快乐。

答案 1 :(得分:1)

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

如果在主体中放入案例2 derived d;,则会得到与案例1相同的错误,因为链接器必须创建派生成员函数定义,并且需要~base()body作为在案例1中。