未定义符号“vtable for ...”和“typeinfo for ...”是什么意思?

58

接近最后一步,但仍然存在一些奇怪的错误...

bash-3.2$ make
g++ -Wall -c -g Myworld.cc
g++ -Wall -g solvePlanningProblem.o Position.o AStarNode.o PRM.o PRMNode.o World.o SingleCircleWorld.o Myworld.o RECTANGLE.o CIRCLE.o -o solvePlanningProblem
Undefined symbols:
  "vtable for Obstacle", referenced from:
      Obstacle::Obstacle()in Myworld.o
  "typeinfo for Obstacle", referenced from:
      typeinfo for RECTANGLEin RECTANGLE.o
      typeinfo for CIRCLEin CIRCLE.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [solvePlanningProblem] Error 1

vtable和typeinfo的含义是什么?


请记得回到您的原始问题并发布一些代码或回答一些人们在那里问过您的问题。这可能会让您更快地获得结果。 :) - Troubadour
我非常想购买,但网站出了问题。谢谢,我会回来的。 - Lisa
请在此处找到答案!https://dev59.com/5XM_5IYBdhLWcg3wQQpd - Saro Bear
1
其他人提到了发生的真相。然而,尽管一些虚拟函数未被实现,代码文件未放入编译器源文件列表也是可能的原因 :(。 - heLomaN
6个回答

106
如果Obstacle是一个抽象基类,那么请确保声明所有的虚函数都为“纯虚函数”:
virtual void Method() = 0;

= 0告诉编译器此方法必须由派生类重写,可能没有自己的实现。

如果类包含任何非纯虚函数,则编译器会假设它们在某个地方有实现,并且其内部结构(vtable和typeinfo)可能与其中一个对象文件一起生成;如果这些函数未被实现,则内部结构将缺失并且您将收到这些错误。


我在自己的代码中遇到了这个问题。我通过谷歌搜索找到了这个页面,按照你说的修改后问题得到了解决。谢谢! :D - Aishwar
和上面一样 - 在谷歌上找到 - 立刻解决了问题,解决方案快速简单!我在虚函数列表中添加了另一个纯虚成员,却忘记添加 = 0 标记!哎呀 - Marm0t
1
注意:抽象类可以拥有虚方法,并且在同一基类中具有“默认”实现,后继类可以选择覆盖或不覆盖。如果您想使用这样的虚方法,请不要在基类中将它们声明为“纯虚拟”(= 0)。 - mcmlxxxvi

12

类障碍物需要一个虚析构函数。将析构函数定义更改为:

virtual ~Obstacle();

析构函数的定义还会创建带有虚函数的类的vtable。它还确保通过基类指针删除派生类实例时执行正确的操作。
(对问题我该如何处理这个奇怪的错误?的答案副本,该问题似乎是重复的。)

3
在我的情况下,我不仅需要定义析构函数,而且还忘记在我的cpp文件中实现它。 - Ricket
我还需要定义实现方法使其运行。 - code4j

12

还有一种可能导致出现此错误的原因,我想在这里进行记录。我使用的是一个没有RTTI的静态库进行链接。因此,使用C++标志-fno-rtti可以为我解决问题。如果您不需要RTTI,也可以使用此标志。希望这可以帮到您。


1
非常感谢您!我遇到了一个错误,错误信息如下: ld.lld: error: undefined symbol: typeinfo for MySuperClass >>> referenced by SubClass.cpp >>> SubClass.o:(typeinfo for ... in libcore.a) >>> did you mean: vtable for MySuperClass这是因为我在编译第一个库时使用了-fno-rtti选项,但在编译依赖于第一个库的第二个库时忘记设置该选项。 - undefined

4

你是否有一个名为 Obstacle.cc 的文件?如果是这样,你需要确保它被编译成 Obstacle.o 文件,并且在链接程序时将 Obstacle.o 添加到命令行中。

另外,请确保你定义了所有非纯虚方法。如果你声明了一个纯虚析构函数,你也需要定义它。


我必须拥有一个Obstacle.cc文件吗?因为它只有一些虚函数? - Lisa
@Lisa:不一定,但在.h文件中定义非内联非模板方法/函数可能会导致不同的链接器错误(多个定义)。因此,我假设Obstacle中的所有内容都是内联的。您是否编写了Obstacle的所有成员函数的定义,包括构造函数和析构函数?请注意,如果Obstacle具有纯虚析构函数,则仍需要编写其定义。 - bk1e
障碍物类是否只有纯虚函数?撤销这个问题——当涉及到虚表时,这并不重要。你需要一个Obstacle.o文件,这样编译器就有了一个存储Obstacle虚表和类型信息的地方。 - outis
1
@outis:不,你不需要一个目标文件。如果所有的虚成员函数都是内联或纯虚的,那么编译器必须找到一个地方来放置虚表。这通常通过在每个目标文件中生成一个“链接一次”部分来完成。 - Mike Seymour

2

vtable和typeinfo是由C++编译器生成的内部结构。vtable用于调用虚函数,而typeinfo用于RTTI。

不同的编译器在生成这些结构时有不同的策略。我见过的一种策略是,在包含类中第一个虚函数的对象文件中生成表格。


就上述错误而言,未定义的符号是什么意思? - Lisa

1
如果你在子类中错误地声明了方法但忘记实现它,就会出现这个错误。
即使像我一样,在一个中间类中实现了这个方法,这种情况也可能发生。例如,
class Base {
public:
    virtual void func() = 0;
};

class Intermediate : public Base {
public:
    void func(); // implemented in source file
};

class Foo : public Intermediate {
    void func(); // not implemented and so a linker error will occur
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接