为什么调用纯虚函数会导致链接错误而非编译错误?

5

让我有些惊讶的是这个程序:

struct A {
  virtual void a()=0;
};

struct B : public A {
  void a() {}
};

int main() {
  B b;
  b.a(); // OK, call B::a()
  b.A::a(); // linker error?
}

我遇到了这个错误(gcc 4.4):

/tmp/ccfOGuBJ.o: In function `main':
test.cc:(.text+0x28): undefined reference to `A::a()'
collect2: ld returned 1 exit status

(clang 7.0.0)

Undefined symbols for architecture x86_64:
  "A::a()", referenced from:
      _main in test-440cc5.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

我原本以为调用一个被声明为已删除的纯函数会产生显式错误,而不是隐式错误。标准中是否区分“不在此翻译单元中的函数”和“不在任何翻译单元中的函数”?

需要注意的是,在§10.4中没有直接调用纯虚函数的说明。

2个回答

10

纯虚函数可以有函数体。因此,错误是链接错误,因为您未提供函数体。


啊,标准在这种情况下有点误导人,因为它有一行代码:virtual void f() = 0 { }; // ill-formed。这是正确的,但让我误以为纯虚函数不能有实现,而不是简单地混合这些语法不受支持。谢谢! - OmnipotentEntity

9
将函数标记为纯虚函数并不意味着该函数没有实现。这只意味着从您派生的类必须覆盖此特定成员函数或保持抽象。特别地,对于从您派生的类继承和使用的纯虚函数提供实现是完全合法的。
这就是为什么在链接阶段之前无法检测到实现的存在(或不存在):您可以在单独的翻译单位中提供实现,因此编译器可能不知道它的存在。

一个很好的纯虚函数的例子,甚至需要被实现的是某个基类的纯虚析构函数。 - Daniel Jour
1
“这只是意味着从您的类派生的类必须覆盖此特定成员函数[...]”,除非派生类本身是抽象的。 - Christian Hackl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接