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

时间:2016-11-19 09:10:53

标签: c++ vtable

以下代码给出了错误

  

未定义对'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 ompile或汇编源文件,但不链接。它没有给我任何错误和编译好。因此,上述错误是在链接时生成的,而不是编译时生成的。 从我学到的不是编译时创建的vtable。那我为什么不在编译时自己得到错误呢?

4 个答案:

答案 0 :(得分:2)

我使用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

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

错误的根本原因是在{Derid}中声明了test,但实际上并未实现。链接器给出了一个令人困惑的错误消息。它应该为缺少的Derived::test方法声明错误

答案 1 :(得分:2)

编译器并不要求所有方法都可用。这足以让他发表声明。

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

它的链接器作业可以匹配方法和调用。

答案 2 :(得分:2)

但是你形成了一个必须在编译时创建vtable的观点,你错了。

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

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

然后,链接器需要检测缺少函数的定义。

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

答案 3 :(得分:1)

GCC对此问题有FAQ entry

  

构建C ++时,链接器表示构造函数,析构函数或虚拟表未定义,但我定义了它们

     

解决方案是确保定义所有非纯的虚拟方法。请注意,即使将析构函数声明为pure-virtual [class.dtor] / 7,也必须定义析构函数。