为什么必须在基类中定义非纯虚方法?

时间:2016-06-01 14:48:17

标签: c++ linker-errors pure-virtual virtual-method

在这种特殊情况下,为什么我必须在基类中定义非纯虚方法以避免链接器错误?

这会产生链接器错误:

class A
{
  public:
  virtual ~A(){}
  virtual void foo() = 0;
  virtual void bar();
};

class B : public A
{
  public:
  void foo()
  {
  }
  void bar()
  {
  }
};

int main()
{
    B b;
}

输出:

/tmp/cc5E8Tit.o: In function `A::~A()':
:(.text._ZN1AD2Ev[_ZN1AD5Ev]+0x13): undefined reference to `vtable for
A' /tmp/cc5E8Tit.o:(.rodata._ZTI1B[_ZTI1B]+0x10): undefined reference
to `typeinfo for A' collect2: error: ld returned 1 exit status

但是,如果我在类A中定义bar方法,则链接ok:

class A
{
  public:
  virtual ~A(){}
  virtual void foo() = 0;
  virtual void bar(){}
};

class B : public A
{
  public:
  void foo()
  {
  }
  void bar()
  {
  }
};

int main()
{
    B b;
}

...没有链接器错误。

为什么会这样?

3 个答案:

答案 0 :(得分:4)

来自C ++ 11标准:

  

10.3虚拟功能

     

11在一个类中声明的虚函数应在该类中定义或声明为纯(10.4),或两者兼有;但不需要诊断(3.2)。

定义纯虚函数是可以的,但没有必要。

如果声明了虚函数但未声明为纯虚函数,则必须定义虚函数。

即使语言不需要它,链接器也会抱怨。

答案 1 :(得分:3)

R Sahu 已经提供了与此相关的标准报价,我将提供稍微更长的解释为什么会发生错误 - 如果不使用它们,有时你可以不用定义函数,但在这种情况下不会

始终使用虚拟功能。它们的地址用于虚拟表,这些表是为具有虚函数的每个类构建的,用于动态调度。

链接器发出错误,因为基类A构造函数设置指向基类虚拟表的指针,虚拟表包含指向bar的指针,链接器无法找到bar成员函数的定义找到它的地址。

答案 2 :(得分:1)

答案在于定义本身。如果未定义函数,则该函数是纯虚函数。然后,如果您没有将其标记为纯虚拟,则必须对其进行定义。它是C++语言的约束。