我只是遇到了以下错误:
(.gnu.linkonce。[内容]):定义 引用[方法][对象] 文件:(.gnu.linkonce。[内容]): 对' typeinfo for '的未定义引用 (名称)的
为什么可能会得到这些“未定义的引用typeinfo”链接错误之一? 有人能解释一下幕后发生了什么吗?
我只是遇到了以下错误:
(.gnu.linkonce。[内容]):定义 引用[方法][对象] 文件:(.gnu.linkonce。[内容]): 对' typeinfo for '的未定义引用 (名称)的
为什么可能会得到这些“未定义的引用typeinfo”链接错误之一? 有人能解释一下幕后发生了什么吗?
当前回答
在基类(抽象基类)中声明虚析构函数,因为不能将析构函数声明为纯虚函数,所以要么必须在抽象类中定义它,就像virtual ~base(){}这样的虚拟定义,要么在任何派生类中定义。
如果你没有做到这一点,你将在链接时以一个“未定义的符号”结束。 因为VMT在根据派生类中的实现更新表时,为所有纯虚函数提供了一个带有匹配NULL的条目。但对于非纯虚函数,则需要在链接时定义,以便更新VMT表。
使用c++filt来要求符号。比如$c++filt _ZTIN10storageapi8BaseHostE 将输出类似"typeinfo for storageapi::BaseHost"的内容。
其他回答
在基类(抽象基类)中声明虚析构函数,因为不能将析构函数声明为纯虚函数,所以要么必须在抽象类中定义它,就像virtual ~base(){}这样的虚拟定义,要么在任何派生类中定义。
如果你没有做到这一点,你将在链接时以一个“未定义的符号”结束。 因为VMT在根据派生类中的实现更新表时,为所有纯虚函数提供了一个带有匹配NULL的条目。但对于非纯虚函数,则需要在链接时定义,以便更新VMT表。
使用c++filt来要求符号。比如$c++filt _ZTIN10storageapi8BaseHostE 将输出类似"typeinfo for storageapi::BaseHost"的内容。
一个可能的原因是声明了虚函数而没有定义它。
当你声明它而没有在同一个编译单元中定义它时,你就表明它在其他地方定义了——这意味着链接器阶段将尝试在其他编译单元(或库)中找到它。
定义虚函数的一个例子是:
virtual void fn() { /* insert code here */ }
在本例中,您将定义附加到声明中,这意味着链接器稍后不需要解析它。
这条线
virtual void fn();
声明fn()而不定义它,这将导致您所要求的错误消息。
它与代码非常相似:
extern int i;
int *pi = &i;
它声明整数I在另一个编译单元中声明,必须在链接时解析(否则PI不能设置为它的地址)。
与上面的RTTI、NO-RTTI讨论类似,如果使用dynamic_cast而未能包含包含类实现的目标代码,也会发生此问题。
我在Cygwin上构建代码时遇到了这个问题,然后将代码移植到Linux上。make文件、目录结构甚至gcc版本(4.8.2)在这两种情况下都是相同的,但是代码在Cygwin上可以正确链接和操作,但在Linux上却无法链接。Red Hat Cygwin显然已经对编译器/链接器进行了修改,以避免目标代码链接需求。
Linux链接器错误消息正确地将我引导到dynamic_cast行,但本论坛早期的消息让我寻找缺少的函数实现,而不是实际的问题:缺少目标代码。我的解决方法是在基类和派生类中替换一个虚拟类型函数,例如virtual int isSpecialType(),而不是使用dynamic_cast。这种技术避免了仅仅为了使dynamic_cast正常工作而链接对象实现代码的需求。
在我的情况下,这纯粹是一个库依赖问题,即使我有dynamic_cast调用。在makefile中添加了足够的依赖后,这个问题就消失了。
如果你要将一个。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 "。这使得编译器和链接器的事情变得复杂,可能会损害代码的性能。