对内联构造函数影响的vtable错误的未定义引用

时间:2012-08-23 12:40:29

标签: c++ constructor compiler-errors g++ vtable

虽然堆栈溢出还有其他问题,这些问题涉及'未定义的vtable引用'错误消息。以下代码编译或不编译,具体取决于no-args构造函数C()是否在线实现。我知道成员函数m()应该是纯虚拟的,并且这是正确的更改,以便解决问题。令我感到困惑的是,它可以通过明显不相关的变化进行编译。

以下代码不能用g ++编译(在ubuntu 64位上为4.6.3)并产生预期的'未定义的对vtable for C'消息的引用(对于记录来说仍然是一个可怕的错误消息,考虑到问题是m ())

Header.h

#ifndef HEADER_H
#define HEADER_H

class C
{
  public:
    C();
    virtual void m();
};

#endif

Implementation.cpp

#include "Header.h"
C::C() {}

Main.cpp的

#include "Header.h"
int main()
{
   return 0;
}

以下不相关的更改允许编译:

  • 从Implementation.cpp
  • 中删除C :: C()的非内联实现
  • 为Header.h中的类添加C()的简单内联实现

为什么这允许编译?这是编译器错误,优化器问题还是标准难题的黑暗角落?

1 个答案:

答案 0 :(得分:7)

  

这是编译器错误,优化器问题还是标准难题的黑暗角落?

以上都不是。这不是一个错误,它与优化无关,而且这个特殊问题超出了标准的范围,它由相关的ABI(这只是事实上的标准)所涵盖。

C::mkey function,你没有在任何地方定义它,这意味着编译器不会发出vtable。

有很好的(如果复杂的)原因,为什么代码会编译这些更改:

  
      
  • 从Implementation.cpp
  • 中删除C :: C()的非内联实现   

由于ABI文档中2.6中描述的一些复杂原因,在构建期间需要vtable。因此构造函数的定义创建了对vtable的引用,链接器告诉您在链接时缺少该引用。如果删除构造函数的定义,则不会引用vtable。

  
      
  • 为Header.h中的类添加C()的简单内联实现
  •   

在给定的转换单元中未调用的内联函数将不会在目标文件中发出,因此使函数内联意味着构造函数不在目标文件中,因此目标文件不引用vtable,链接器不需要在链接时查找它。

如果您更改程序以便实际使用内联构造函数(例如,通过在C中创建main),那么您将再次获得相同的链接器错误,因为现在内联构造函数将在Main.o中定义,因此需要vtable。

class C
{
  public:
    C() { }  // inline
    virtual void m();
};

int main()
{
    C c;
}