我刚遇到了以下错误:
(.gnu.linkonce.[stuff]):未定义的 参考 [method] [object file]:(.gnu.linkonce.[stuff]): 未定义对于`[classname]`的typeinfo的引用
为什么会出现这种“未定义对于typeinfo的引用”的链接器错误?
有人能解释一下背后发生了什么吗?
可能的一个原因是你声明了一个虚函数但没有定义它。
当你在同一编译单元中声明但未定义虚函数时,你表明它在其他地方被定义了 - 这意味着链接器将尝试在其他编译单元(或库)中找到它。
定义虚函数的一个例子是:
virtual void fn() { /* insert code here */ }
在这种情况下,您正在将定义附加到声明,这意味着链接器不需要稍后解析它。virtual void fn();
这段代码声明了fn()
,但没有定义它,会导致你所询问的错误信息。
与以下代码非常相似:
extern int i;
int *pi = &i;
这说明整数变量i
是在另一个编译单元中声明的,必须在链接时解析(否则pi
无法设置为它的地址)。
virtual void fn() = 0
是一个定义是不正确的。它只是一种 声明。链接器没有试图解析它的唯一原因是相应的虚函数表(VMT)条目不会引用函数体(很可能包含空指针)。然而,你可以以非虚拟方式调用这个纯虚函数,即使用全限定名。在这种情况下,链接器将寻找函数体,你需要定义该函数。而且,你确实可以为纯虚函数定义函数体。 - AnT stands with Russia-fno-rtti
被指定为编译器选项,而不是因为虚函数未定义。我认为这个答案的引言声明"This particular error is caused by..."有点误导人,更好的说法应该是"One possible reason is because..."。 - gbmhunter-fno-rtti
和-frtti
代码时。这时,您需要确保在-frtti
代码中访问type_info
的任何类都使用-frtti
编译其关键方法。当您创建该类的对象、使用dynamic_cast
等时,就会出现这种访问情况。当声明了(非纯)虚函数但未提供函数主体时,会出现此问题。在类定义中,可能存在以下代码:
virtual void foo();
应该被定义(内联或在链接的源文件中):
virtual void foo() {}
或者声明为纯虚函数:
virtual void foo() = 0;
__attribute__ ((visibility("default")))
在类声明中。例如,class __attribute__ ((visibility("default"))) boom{
virtual void stick();
}
另一种解决方案,当然是不使用“-fvisibility=hidden”。这会让编译器和链接器变得更复杂,可能会影响代码性能。
之前的回答是正确的,但这个错误也可能是由于尝试在没有虚函数的类对象上使用typeid而引起的。C++ RTTI需要一个vtable,因此您希望执行类型识别的类需要至少一个虚函数。
如果你想让某个类的类型信息工作,但又不想真正使用任何虚函数,请将析构函数声明为virtual。
我刚刚花了几个小时来解决这个错误,虽然这里其他答案帮助我理解了情况,但并没有解决我的具体问题。
我正在开发一个使用clang++
和g++
编译的项目。使用clang++
时没有任何链接问题,但是使用g++
时遇到了undefined reference to 'typeinfo for
的错误。
重要提示:在使用g++
进行链接时,链接顺序很重要。如果你以不正确的顺序列出要连接的库,就会出现typeinfo
错误。
有关使用gcc
/g++
链接顺序的更多详细信息,请参见此 SO 问题。
clang
时链接顺序也很重要,因此这个建议是普适的,谢谢。 - Fedor处理 RTTI 和非 RTTI 库的代码可能的解决方案:
a)重新编译所有内容,要么使用 -frtti ,要么使用 -fno-rtti
b)如果 a)对您不可行,请尝试以下方法:
假设 libfoo 是没有使用 RTTI 构建的。 您的代码使用 libfoo 并使用 RTTI 进行编译。 如果您在 libfoo 中使用具有虚函数的类(Foo),则可能会遇到链接时错误,指出:缺少类 Foo 的类型信息。
定义另一个类(例如 FooAdapter),它没有虚函数并将调用转发到您使用的 Foo。
在一个小的静态库中编译 FooAdapter,该库不使用 RTTI 且仅依赖于 libfoo 符号。为其提供一个头文件,并在您的代码中(使用 RTTI)使用该头文件而不是 libfoo。由于 FooAdapter 没有任何虚函数,因此它不会有任何类型信息,您将能够链接您的二进制文件。如果您从 libfoo 使用了许多不同的类,则此解决方案可能不方便,但这是一个开始。
在我的情况下,出现了一个在接口类中没有被定义为纯虚函数的虚函数。
class IInterface
{
public:
virtual void Foo() = 0;
}
我忘记了= 0
这一位。
virtual void abc() =0;
。 - dhardyabc()
函数,你很容易忘记在派生类中重新定义abc()
,并认为一切都很好,因为你仍然可以无任何问题地调用该函数。一个实现纯虚函数的好做法可以在这篇文章中找到,即让函数打印出 "Pure virtual function called" 然后崩溃程序。 - HelloGoodbye= 0;
。 - dwanderson