C++ g++ 对 typeinfo 的未定义引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/307352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
g++ undefined reference to typeinfo
提问by cdleary
I just ran across the following error (and found the solution online, but it's not present in Stack Overflow):
我刚刚遇到了以下错误(并在网上找到了解决方案,但堆栈溢出中不存在):
(.gnu.linkonce.[stuff]): undefined reference to [method] [object file]:(.gnu.linkonce.[stuff]): undefined reference to `typeinfo for [classname]'
(.gnu.linkonce.[stuff]): 未定义引用 [method] [object file]:(.gnu.linkonce.[stuff]): 未定义引用 `typeinfo for [classname]'
Why might one get one of these "undefined reference to typeinfo" linker errors?
为什么可能会得到这些“对 typeinfo 的未定义引用”链接器错误之一?
(Bonus points if you can explain what's going on behind the scenes.)
(如果你能解释幕后发生的事情,加分。)
回答by paxdiablo
One possible reason is because you are declaring a virtual function without defining it.
一个可能的原因是因为您声明了一个虚函数而没有定义它。
When you declare it without defining it in the same compilation unit, you're indicating that it's defined somewhere else - this means the linker phase will try to find it in one of the other compilation units (or libraries).
当你声明它而不在同一个编译单元中定义它时,你表明它是在其他地方定义的 - 这意味着链接器阶段将尝试在其他编译单元(或库)之一中找到它。
An example of defining the virtual function is:
定义虚函数的一个例子是:
virtual void fn() { /* insert code here */ }
In this case, you are attaching a definition to the declaration, which means the linker doesn't need to resolve it later.
在这种情况下,您将定义附加到声明中,这意味着链接器稍后不需要解析它。
The line
线
virtual void fn();
declares fn()
without defining it and will cause the error message you asked about.
声明fn()
而不定义它,并会导致您询问的错误消息。
It's very similar to the code:
它与代码非常相似:
extern int i;
int *pi = &i;
which states that the integer i
is declared in another compilation unit which must be resolved at link time (otherwise pi
can't be set to it's address).
它指出整数i
是在另一个编译单元中声明的,必须在链接时解析(否则pi
不能设置为它的地址)。
回答by Sergiy Belozorov
This can also happen when you mix -fno-rtti
and -frtti
code. Then you need to ensure that any class, which type_info
is accessed in the -frtti
code, have their key method compiled with -frtti
. Such access can happen when you create an object of the class, use dynamic_cast
etc.
当您混合-fno-rtti
和-frtti
编码时,也会发生这种情况。然后,您需要确保type_info
在-frtti
代码中访问的任何类的关键方法都使用-frtti
. 当您创建类的对象、使用dynamic_cast
等时,可能会发生这种访问。
[source]
[来源]
回答by cdleary
This occurs when declared (non-pure) virtual functions are missing bodies. In your class definition, something like:
当声明的(非纯)虚函数缺少主体时,就会发生这种情况。在您的类定义中,类似于:
virtual void foo();
Should be defined (inline or in a linked source file):
应该定义(内联或在链接的源文件中):
virtual void foo() {}
Or declared pure virtual:
或声明纯虚拟:
virtual void foo() = 0;
回答by CesarB
Quoting from the gcc manual:
引用gcc 手册:
For polymorphic classes (classes with virtual functions), the type_info object is written out along with the vtable [...] For all other types, we write out the type_info object when it is used: when applying `typeid' to an expression, throwing an object, or referring to a type in a catch clause or exception specification.
对于多态类(具有虚函数的类),type_info 对象与 vtable 一起写出 [...] 对于所有其他类型,我们在使用时写出 type_info 对象:当将 `typeid' 应用于表达式时,抛出一个对象,或者在 catch 子句或异常规范中引用一个类型。
And a bit earlier on the same page:
在同一页面上稍早一点:
If the class declares any non-inline, non-pure virtual functions, the first one is chosen as the “key method” for the class, and the vtable is only emitted in the translation unit where the key method is defined.
如果类声明了任何非内联、非纯虚函数,则选择第一个作为类的“关键方法”,并且 vtable 仅在定义关键方法的翻译单元中发出。
So, this error happens when the "key method" is missing its definition, as other answers already mentioned.
因此,正如其他答案已经提到的那样,当“关键方法”缺少其定义时,就会发生此错误。
回答by human
If you're linking one .so to another, yet one more possibility is compiling with "-fvisibility=hidden" in gcc or g++. If both .so files were built with "-fvisibility=hidden" and the key method is not in the same .so as another of the virtual function's implementations, the latter won't see the vtable or typeinfo of the former. To the linker, this looks like an unimplemented virtual function (as in paxdiablo's and cdleary's answers).
如果您将一个 .so 链接到另一个 .so,还有一种可能性是在 gcc 或 g++ 中使用“-fvisibility=hidden”进行编译。如果两个 .so 文件都是使用“-fvisibility=hidden”构建的,并且关键方法与另一个虚函数的实现不在同一个 .so 中,则后者将看不到前者的 vtable 或 typeinfo。对于链接器来说,这看起来像是一个未实现的虚函数(如 paxdiablo 和 cdleary 的答案)。
In this case, you must make an exception for the visibility of the base class with
在这种情况下,您必须对基类的可见性进行例外处理
__attribute__ ((visibility("default")))
in the class declaration. For instance,
在类声明中。例如,
class __attribute__ ((visibility("default"))) boom{
virtual void stick();
}
Another solution, of course, is to not use "-fvisibility=hidden." That does complicate things for the compiler and linker, possibly to the detriment of code performance.
当然,另一个解决方案是不使用“-fvisibility=hidden”。这确实使编译器和链接器的事情变得复杂,可能会损害代码性能。
回答by Tyler McHenry
The previous answers are correct, but this error can also be caused by attempting to use typeid on an object of a class that has novirtual functions. C++ RTTI requires a vtable, so classes that you wish to perform type identification on require at least one virtual function.
前面的答案是正确的,但是尝试在没有虚函数的类的对象上使用 typeid 也可能导致此错误。C++ RTTI 需要一个 vtable,因此您希望对其执行类型识别的类至少需要一个虚函数。
If you want type information to work on a class for which you don't really want any virtual functions, make the destructor virtual.
如果您希望类型信息适用于您并不真正想要任何虚函数的类,请将析构函数设为虚函数。
回答by dinkelk
I just spent a few hours on this error, and while the other answers here helped me understand what was going on, they did not fix my particular problem.
我只是在这个错误上花了几个小时,虽然这里的其他答案帮助我了解发生了什么,但它们并没有解决我的特定问题。
I am working on a project that compiles using both clang++
and g++
. I was having no linking issues using clang++
, but was getting the undefined reference to 'typeinfo for
error with g++
.
我正在开发一个使用clang++
和编译的项目g++
。我在使用 时没有链接问题clang++
,但在undefined reference to 'typeinfo for
使用g++
.
The important point:Linking order MATTERS with g++
. If you list the libraries you want to link in an order which is incorrect you can get the typeinfo
error.
重点:将订单事项与g++
. 如果您以不正确的顺序列出要链接的库,则会typeinfo
出现错误。
See this SO questionfor more details on linking order with gcc
/g++
.
有关将订单与/链接的更多详细信息,请参阅此 SO 问题。gcc
g++
回答by Francois
Possible solutions for code that deal with RTTI and non-RTTI libraries:
处理 RTTI 和非 RTTI 库的代码的可能解决方案:
a) Recompile everything with either -frtti or -fno-rtti
b) If a) is not possible for you, try the following:
a) 使用 -frtti 或 -fno-rtti 重新编译所有内容
b) 如果 a) 不适合您,请尝试以下操作:
Assume libfoo is built without RTTI. Your code uses libfoo and compiles with RTTI. If you use a class (Foo) in libfoo that has virtuals, you're likely to run into a link-time error that says: missing typeinfo for class Foo.
假设 libfoo 是在没有 RTTI 的情况下构建的。您的代码使用 libfoo 并使用 RTTI 进行编译。如果您在 libfoo 中使用具有 virtuals 的类 (Foo),您可能会遇到链接时错误,提示:缺少类 Foo 的类型信息。
Define another class (e.g. FooAdapter) that has no virtual and will forward calls to Foo that you use.
定义另一个没有虚拟的类(例如 FooAdapter),并将调用转发到您使用的 Foo。
Compile FooAdapter in a small static library that doesn't use RTTI and only depends on libfoo symbols. Provide a header for it and use that instead in your code (which uses RTTI). Since FooAdapter has no virtual function it won't have any typeinfo and you'll be able to link your binary. If you use a lot of different classes from libfoo, this solution may not be convenient, but it's a start.
在一个不使用 RTTI 且仅依赖于 libfoo 符号的小型静态库中编译 FooAdapter。为它提供一个标头并在您的代码中使用它(使用 RTTI)。由于 FooAdapter 没有虚函数,它不会有任何类型信息,您将能够链接您的二进制文件。如果你使用了很多来自 libfoo 的不同类,这个解决方案可能不方便,但它是一个开始。
回答by FNE
Similarly to the RTTI, NO-RTTI discussion above, this problem can also occur if you use dynamic_cast and fail to include the object code containing the class implementation.
与上面讨论的 RTTI、NO-RTTI 类似,如果您使用 dynamic_cast 并且未能包含包含类实现的对象代码,也会出现此问题。
I ran into this problem building on Cygwin and then porting code to Linux. The make files, directory structure and even the gcc versions (4.8.2) were identical in both cases, but the code linked and operated correctly on Cygwin but failed to link on Linux. Red Hat Cygwin has apparently made compiler/linker modifications that avoid the object code linking requirement.
我在 Cygwin 上构建然后将代码移植到 Linux 时遇到了这个问题。在这两种情况下,make 文件、目录结构甚至 gcc 版本 (4.8.2) 都是相同的,但代码在 Cygwin 上链接和操作正确,但在 Linux 上链接失败。Red Hat Cygwin 显然对编译器/链接器进行了修改,以避免目标代码链接要求。
The Linux linker error message properly directed me to the dynamic_cast line, but earlier messages in this forum had me looking for missing function implementations rather than the actual problem: missing object code. My workaround was to substitute a virtual type function in the base and derived class, e.g. virtual int isSpecialType(), rather than use dynamic_cast. This technique avoids the requirement to link object implementation code just to get dynamic_cast to work properly.
Linux 链接器错误消息正确地将我定向到 dynamic_cast 行,但本论坛的早期消息让我寻找缺少的函数实现而不是实际问题:缺少目标代码。我的解决方法是在基类和派生类中替换一个虚拟类型函数,例如 virtual int isSpecialType(),而不是使用 dynamic_cast。这种技术避免了为了让 dynamic_cast 正常工作而链接对象实现代码的要求。
回答by Prashanth
In the base class (an abstract base class) you declare a virtual destructor and as you cannot declare a destructor as a pure virtual function, either you have to define it right here in the abstract class, just a dummy definition like virtual ~base() { } will do, or in any of the derived class.
在基类(抽象基类)中,您声明了一个虚拟析构函数,并且由于您不能将析构函数声明为纯虚函数,因此您必须在抽象类中就在这里定义它,只是一个虚拟的定义,如 virtual ~base( ){} 都可以,或者在任何派生类中。
If you fail to do this, you will end up in an "undefined symbol" at link time. Since VMT has an entry for all the pure virtual functions with a matching NULL as it updates the table depending on the implementation in the derived class. But for the non-pure but virtual functions, it needs the definition at the link time so that it can update the VMT table.
如果你不这样做,你将在链接时得到一个“未定义的符号”。由于 VMT 具有所有纯虚函数的条目,并且具有匹配的 NULL,因为它根据派生类中的实现更新表。但对于非纯但虚函数,则需要在链接时进行定义,以便更新 VMT 表。
Use c++filt to demangle the symbol. Like $c++filt _ZTIN10storageapi8BaseHostE will output something like "typeinfo for storageapi::BaseHost".
使用 c++filt 对符号进行解码。像 $c++filt _ZTIN10storageapi8BaseHostE 会输出类似“typeinfo for storageapi::BaseHost”的内容。