2016-11-19 56 views
2

在下面的代码段给我错误如果vtable是在编译时创建的,为什么这个错误是链接器错误而不是编译错误?

未定义参考`虚表为衍生”

代码:

#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; 
} 

我理解是因为虚拟温控功能testclass Derived中声明但未定义。

但是当我g++ -c file.cpp编译其按thisçompile或汇编源文件,但不链接。它不会给我任何错误并编译好。因此,上述错误产生于链接时间而不是编译时间。 从我学到的不是在编译时创建的vtable。那为什么我在编译时本身没有得到这个错误呢?

+0

错误来自链接程序,因为时间的检查会显示给您。 – EJP

+0

@EJP是的,我确实意识到这一点,并且对问题本身进行了描述。但我不明白的是,我不应该在编译时自己gettng而不是链接。 – Hummingbird

+2

“编译时”的描述包括链接时间,但不包括运行时 –

回答

2

但是,您认为在编译时必须创建一个vtable,这是错误的。

单独编译是标准中的核心概念。这是编译单元(又名源文件)可以编译的原因,只要它声明了所需的函数即使它没有定义的可见性。

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

接下来需要检测到函数定义的缺失。

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

+0

谢谢..现在我想我明白它...和vtable部分我从[这里]参考(http://stackoverflow.com/questions/3849498/当-vtable-in-c-created) – Hummingbird

+0

该链接只是说,创建的vtable是由实现来处理的。它并没有说它只在编译期间发生。在“编译然后链接”工具链中,链接器是实现的一个组件。 – Peter

+0

我同意你的观点,虽然链接确实说引用** vtables是在编译时创建的结构**反正这让我感到困惑。 – Hummingbird

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 

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

错误的根本原因是在Derived中声明了test,但未实际执行。链接器提供了一个令人困惑的错误消息。应宣布一个错误失踪Derived::test方法

+0

这就是为什么这是链接器错误的确切问题?从我学到的vtable是在编译时创建的?所以很好理解为什么我在编译时本身并没有在连接的时候得到错误。 – Hummingbird

1

GCC有针对此问题的FAQ entry

当建立C++中,连接说我的构造函数,析构函数或虚表是不确定的,但我定义它们

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

+0

谢谢,我明白这一点,但我无法理解的是,“如果vtable是在编译时创建的,那么为什么我不会得到这个错误也只是编译时间,而是在连接时间。”如果那不是太多问。 – Hummingbird

+1

@DevanshMohanKaushik vtable由编译器分配并由链接器初始化。看起来像彼得斯详细描述了这一点。 – Nikita

+0

是的,那是什么我感到困惑..谢谢不管怎样 – Hummingbird

2

编译器不需要有所有可用的方法。他有足够的声明。

该方法可以在不同的编译单元(cpp/cxx文件)中实现,因此编译器甚至不可能检查此方法是否可用。编译器在处理一个cpp文件。

这是连接器的工作,以匹配方法和调用。