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



虽然还有其他关于堆栈溢出的问题,这些问题处理"对vtable的未定义引用"错误消息。以下代码编译或不编译取决于无参数构造函数C()是否在内联中实现。我知道成员函数m()应该是纯虚拟的,这将是为了解决问题而进行的正确更改。让我困惑的是,它可以通过一个明显不相关的更改进行编译。

以下代码不使用g++(在ubuntu 64位上为4.6.3)进行编译,并产生预期的"C的vtable的未定义引用"消息(记录在案,考虑到m()的问题,这仍然是一个可怕的错误消息)

收割台.h

#ifndef HEADER_H
#define HEADER_H
class C
{
  public:
    C();
    virtual void m();
};
#endif

实施.cpp

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

主要.cpp

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

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

  • 从implementation.cpp中删除C::C()的非内联实现
  • 将C()的琐碎内联实现添加到Header.h中的类中

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

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

以上都没有。这不是一个错误,与优化无关,而且这个特定问题不在标准范围内,它包含在相关的ABI中(这只是一个事实上的标准)

C::m是关键函数,您在任何地方都没有定义它,这意味着编译器不会发出vtable。

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

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

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

  • 将C()的琐碎内联实现添加到Header.h中的类中

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

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

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

最新更新