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

Dun*_*ter 5 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
Run Code Online (Sandbox Code Playgroud)

Implementation.cpp

#include "Header.h"
C::C() {}
Run Code Online (Sandbox Code Playgroud)

Main.cpp的

#include "Header.h"
int main()
{
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

以下无关的更改允许编译:

  • 从Implementation.cpp中删除C :: C()的非内联实现
  • 在Header.h中为C()添加琐碎的内联实现

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

Jon*_*ely 7

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

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

C::m关键功能,你没有在任何地方定义它,这意味着编译器不会发出vtable.

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

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

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

  • 在Header.h中为C()添加琐碎的内联实现

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

如果改变这样的直列构造实际使用的程序(例如,通过创建一个Cmain),那么你会回来得到同样的连接错误,因为现在的直列构造函数中定义Main.o,因此需要的虚函数表.

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

int main()
{
    C c;
}
Run Code Online (Sandbox Code Playgroud)