在这种特殊情况下,为什么我必须在基类中定义非纯虚方法以避免链接器错误?
这会产生链接器错误:
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;
}
...没有链接器错误。
为什么会这样?
答案 0 :(得分:4)
来自C ++ 11标准:
10.3虚拟功能
11在一个类中声明的虚函数应在该类中定义或声明为纯(10.4),或两者兼有;但不需要诊断(3.2)。
定义纯虚函数是可以的,但没有必要。
如果声明了虚函数但未声明为纯虚函数,则必须定义虚函数。
即使语言不需要它,链接器也会抱怨。
答案 1 :(得分:3)
R Sahu 已经提供了与此相关的标准报价,我将提供稍微更长的解释为什么会发生错误 - 如果不使用它们,有时你可以不用定义函数,但在这种情况下不会
始终使用虚拟功能。它们的地址用于虚拟表,这些表是为具有虚函数的每个类构建的,用于动态调度。
链接器发出错误,因为基类A
构造函数设置指向基类虚拟表的指针,虚拟表包含指向bar
的指针,链接器无法找到bar
成员函数的定义找到它的地址。
答案 2 :(得分:1)
答案在于定义本身。如果未定义函数,则该函数是纯虚函数。然后,如果您没有将其标记为纯虚拟,则必须对其进行定义。它是C++
语言的约束。