如果 vtable 是在编译时创建的,为什么这个错误是链接器错误而不是编译错误?

if vtable is created at compile time , why this error is an linker error and not compile error?

下面的一段代码报错了

undefined reference to `vtable for Derived'

代码:

#include <iostream>
class base{
    public:
    base(){}
    virtual ~base(){}
    virtual void test()
    {
    }
};
class Derived:public base{
    public:
    Derived(){}
    ~Derived(){}  
    void test();
};
int main() {
    base* b = new Derived ();
    delete b;
}

我的理解是因为 虚函数 test 已声明但未在 class Derived.

中定义

但是当我使用 g++ -c file.cpp 编译时,根据 this C 编译或 assemble 源文件,但不 link。它不会给我任何错误并且可以正常编译。因此,上述错误是在 linking 时间而不是 compile 时间生成的。 据我了解, vtable 不是在编译时创建的。那为什么我在编译时自己没有得到错误?

我得到了什么 g++ foo.cpp -v

/tmp/ccBc4VPu.o: In function `Derived::Derived()':
foo.cpp:(.text._ZN7DerivedC2Ev[_ZN7DerivedC5Ev]+0x1f): undefined reference to `vtable for Derived'
collect2: error: ld returned 1 exit status

这是一个 链接器 错误,本身不是编译器错误。

错误的根本原因是test是在Derived中声明的,但并没有真正实现。链接器给出了令人困惑的错误消息。它应该为缺少的 Derived::test 方法

声明一个错误

GCC 有一个 FAQ entry 解决这个问题:

When building C++, the linker says my constructors, destructors or virtual tables are undefined, but I defined them

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7.

编译器不需要所有方法都可用。他有他们的宣言就够了。

此方法可以在不同的编译单元(cpp/cxx 文件)中实现,因此对于编译器而言,甚至无法检查此方法是否在其他地方可用。编译器一次处理一个 cpp 文件。

将方法和调用匹配在一起是链接器的工作。

然而你形成了必须在编译时创建 vtable 的观点,你错了。

分离编译是标准中的一个核心概念。这就是编译单元(又名源文件)可以编译的原因,只要它需要任何函数声明 - 即使它没有定义的可见性。

在典型的 "compile then link" 构建链中,这允许编译单元(源文件)进行编译,给定可能在另一个编译单元中定义的函数(成员函数或非成员函数)的任何声明。

链接器需要检测函数定义的缺失。

实际上,这意味着编译器可能会发出有关 vtable 的信息,但链接器将(咳咳)将 vtable 的规范链接到实际的成员函数。