我只是遇到了以下错误:

(.gnu.linkonce。[内容]):定义 引用[方法][对象] 文件:(.gnu.linkonce。[内容]): 对' typeinfo for '的未定义引用 (名称)的

为什么可能会得到这些“未定义的引用typeinfo”链接错误之一? 有人能解释一下幕后发生了什么吗?


当前回答

在基类(抽象基类)中声明虚析构函数,因为不能将析构函数声明为纯虚函数,所以要么必须在抽象类中定义它,就像virtual ~base(){}这样的虚拟定义,要么在任何派生类中定义。

如果你没有做到这一点,你将在链接时以一个“未定义的符号”结束。 因为VMT在根据派生类中的实现更新表时,为所有纯虚函数提供了一个带有匹配NULL的条目。但对于非纯虚函数,则需要在链接时定义,以便更新VMT表。

使用c++filt来要求符号。比如$c++filt _ZTIN10storageapi8BaseHostE 将输出类似"typeinfo for storageapi::BaseHost"的内容。

其他回答

在我的例子中,我使用了带有头文件等文件的第三方库。我子类化了一个类,当我尝试实例化我的子类时,发生了这样的链接错误。

正如@sergiy所提到的,知道这可能是“rtti”的问题,我设法通过将构造函数实现放在单独的.cpp文件中并将“-fno-rtti”编译标志应用到文件中来解决它。它工作得很好。

由于我仍然不太清楚这个链接错误的内部,我不确定我的解决方案是否通用。然而,我认为在尝试@francois提到的适配器方式之前值得一试。当然,如果所有源代码都可用(不是在我的情况下),最好在可能的情况下使用'-frtti'重新编译。

还有一件事,如果你选择尝试我的解决方案,试着让单独的文件尽可能简单,不要使用c++的一些花哨的功能。特别注意boost相关的事情,因为它很大程度上依赖于rtti。

如果你要将一个。so链接到另一个。so,还有一种可能性是在gcc或g++中使用"-fvisibility=hidden"进行编译。如果两个.so文件都是用"-fvisibility=hidden"构建的,并且key方法不相同。so作为另一个虚函数的实现,后者将看不到前者的虚表或typeinfo。对于链接器来说,这看起来像一个未实现的虚函数(就像paxdiablo和cdleary的答案一样)。

在这种情况下,必须为基类的可见性做出例外

__attribute__ ((visibility("default")))

在类声明中。例如,

class __attribute__ ((visibility("default"))) boom{
    virtual void stick();
}

当然,另一个解决方案是不使用"-fvisibility=hidden "。这使得编译器和链接器的事情变得复杂,可能会损害代码的性能。

当声明的(非纯)虚函数缺少主体时,就会发生这种情况。在你的类定义中,如下所示:

virtual void foo();

应该定义(内联或链接源文件中):

virtual void foo() {}

或声明为纯虚拟的:

virtual void foo() = 0;

当混合使用-fno-rtti和-frtti代码时也会发生这种情况。然后,您需要确保在-frtti代码中访问type_info的任何类都使用-frtti编译了它们的key方法。这种访问可以发生在创建类的对象时,使用dynamic_cast等。

(来源)

一个可能的原因是声明了虚函数而没有定义它。

当你声明它而没有在同一个编译单元中定义它时,你就表明它在其他地方定义了——这意味着链接器阶段将尝试在其他编译单元(或库)中找到它。

定义虚函数的一个例子是:

virtual void fn() { /* insert code here */ }

在本例中,您将定义附加到声明中,这意味着链接器稍后不需要解析它。

这条线

virtual void fn();

声明fn()而不定义它,这将导致您所要求的错误消息。

它与代码非常相似:

extern int i;
int *pi = &i;

它声明整数I在另一个编译单元中声明,必须在链接时解析(否则PI不能设置为它的地址)。