我只是遇到了以下错误(并在线找到了解决方案,但它在Stack Overflow中不存在):
(.gnu.linkonce.[stuff]):对[方法] [目标文件]的未定义引用:(.gnu.linkonce.[stuff]):对[classname]的`typeinfo的未定义引用
为什么可能会得到这些"未定义的typeinfo引用"链接器错误之一?
(如果你能解释幕后发生的事情,可以给予奖励.)
一个可能的原因是因为您在没有定义虚拟函数的情况下声明它.
如果在没有在同一个编译单元中定义它的情况下声明它,则表明它已在其他地方定义 - 这意味着链接器阶段将尝试在其他编译单元(或库)中找到它.
定义虚函数的一个示例是:
virtual void fn() { /* insert code here */ }
在这种情况下,您将一个定义附加到声明,这意味着链接器以后不需要解析它.
这条线
virtual void fn();
声明fn()
而不定义它,并将导致您询问的错误消息.
它与代码非常相似:
extern int i; int *pi = &i;
表明整数i
是在另一个编译单元中声明的,必须在链接时解析(否则pi
不能设置为它的地址).
混合-fno-rtti
和-frtti
编码时也会发生这种情况.然后,您需要确保type_info
在-frtti
代码中访问的任何类都使用其密钥方法进行编译-frtti
.当您创建类的对象,使用dynamic_cast
等时,可能会发生此类访问.
[ 来源 ]
当声明的(非纯)虚函数缺少实体时会发生这种情况.在您的类定义中,类似于:
virtual void foo();
应该定义(内联或链接的源文件):
virtual void foo() {}
或者声明纯虚拟:
virtual void foo() = 0;
引用gcc手册:
对于多态类(具有虚函数的类),type_info对象与vtable一起写出[...]对于所有其他类型,我们在使用时写出type_info对象:当将`typeid'应用于表达式时,抛出一个对象,或引用一个catch子句或异常规范中的类型.
在同一页面上稍早一点:
如果类声明任何非内联非纯虚函数,则选择第一个作为类的"键方法",并且仅在定义键方法的转换单元中发出vtable.
因此,当"密钥方法"缺少其定义时会发生此错误,正如已经提到的其他答案一样.
如果你将一个.so链接到另一个,那么还有一种可能性是用gcc或g ++中的"-fvisibility = hidden"进行编译.如果两个.so文件都是使用"-fvisibility = hidden"构建的,并且key方法与另一个虚函数的实现不同,那么后者将不会看到前者的vtable或typeinfo.对于链接器,这看起来像一个未实现的虚函数(如paxdiablo和cdleary的答案).
在这种情况下,您必须为基类的可见性设置例外
__attribute__ ((visibility("default")))
在课堂宣言中.例如,
class __attribute__ ((visibility("default"))) boom{ virtual void stick(); }
当然,另一种解决方案是不使用"-fvisibility = hidden".这确实使编译器和链接器复杂化,可能会损害代码性能.
以前的答案是正确的,但是这个错误也可能是由于尝试在没有虚函数的类的对象上使用typeid引起的.C++ RTTI需要一个vtable,因此您希望执行类型识别的类至少需要一个虚函数.
如果您希望类型信息适用于您不想要任何虚函数的类,请将析构函数设置为虚拟.
我只花了几个小时来解决这个错误,虽然这里的其他答案帮助我理解了发生了什么,但他们并没有解决我的特殊问题.
我正在开发一个使用clang++
和编译的项目g++
.我没有使用链接问题clang++
,但是得到了undefined reference to 'typeinfo for
错误g++
.
重点:链接订单MATTERS与g++
.如果列出要以不正确的顺序链接的库,则可能会收到typeinfo
错误.
有关将订单与/ 链接的详细信息,请参阅此SO问题.gcc
g++
处理RTTI和非RTTI库的代码的可能解决方案:
a)用-frtti或-fno-rtti重新编译所有内容
b)如果a)不可能,请尝试以下方法:
假设libfoo是在没有RTTI的情况下构建的.您的代码使用libfoo并使用RTTI编译.如果在libfoo中使用具有虚拟的类(Foo),则可能会遇到链接时错误,该错误表示:缺少类Foo的typeinfo.
定义没有虚拟的另一个类(例如FooAdapter),并将调用转发给您使用的Foo.
在不使用RTTI且仅依赖于libfoo符号的小型静态库中编译FooAdapter.为它提供一个标题,并在您的代码中使用它(使用RTTI).由于FooAdapter没有虚函数,因此它不具有任何typeinfo,您将能够链接您的二进制文件.如果你使用libfoo中的很多不同的类,这个解决方案可能不方便,但它是一个开始.
与上面的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正常工作.
在基类(一个抽象基类)中,您声明了一个虚拟析构函数,因为您不能将析构函数声明为纯虚函数,要么您必须在抽象类中定义它,只需要像virtual~base这样的虚拟定义( ){}会做,或者在任何派生类中.
如果您没有这样做,您将在链接时以"未定义的符号"结束.由于VMT具有匹配NULL的所有纯虚函数的条目,因为它根据派生类中的实现更新表.但是对于非纯虚函数,它需要在链接时定义,以便它可以更新VMT表.
使用c ++ filt来解码符号.像$ c ++ filt _ZTIN10storageapi8BaseHostE将输出类似"typeap for storageapi :: BaseHost"的内容.