我该怎么办这个奇怪的错误?

时间:2009-11-07 23:21:42

标签: c++

一切都很好,最后的问题很烦人。编译很棒,但链接失败:

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**

Obstacle.hh

#ifndef Obstacle_hh 
#define Obstacle_hh

#include <vector>
#include <iostream>

class Obstacle{
public:
    Obstacle(){}
    virtual bool collidesWith(double x,double y);
    virtual void writeMatlabDisplayCode(std::ostream &fs);
    virtual ~Obstacle(){}
};
#endif

我有什么问题?我可以发布您需要的任何代码来分析它。

4 个答案:

答案 0 :(得分:4)

您声明了一个非抽象类Obstacle,但您没有实现其所有成员函数。

最好将其声明为抽象类:

class Obstacle{
public:
    Obstacle(){} // this is superfluous, you can (and should) remove it
    virtual bool collidesWith(double x,double y) = 0;
    virtual void writeMatlabDisplayCode(std::ostream &fs) = 0;
    virtual ~Obstacle(){}
};

原因是你会在许多C ++编译器中找到一种启发式方法 - 避免在为第一个非内联虚拟成员函数(如果有的话)定义时创建的类不必要地创建重复的vtable和typeinfos

你的代码填补了这个方案:你将Obstacle.hh包含到某个编译单元中,编译器看到一个类Obstacle,它有collidesWith作为第一个非内联虚拟成员函数,但它不是在当前编译单元中定义,因此编译器认为它可以推迟为类创建vtable和typeinfo。由于没有collidesWith的定义,因此在程序链接时它们最终都会丢失。

答案 1 :(得分:2)

显然你缺少对象文件或库。定义和声明Obstacle对象的那个。

寻找它的好地方是在Myworld中引用的头文件(* .h)文件,因为这将让你知道什么cpp / libraries(通常具有相同的名称)是Myworld使用的对象的基础

编辑,鉴于丽莎的回复:
不,您不需要在源代码中添加任何* .hh文件。问题出在链接时,而不是编译时 是不是有某个Obstacle.cpp文件?这需要编译,并且需要将相应的.o文件添加到make中的最后一个gcc行。

宾果!看到Obstacle.hh后 这两个虚拟方法不是纯虚方法,因此编译器希望它们以某种方式在某处定义。并且还没有定义构造函数和析构函数。
最简单的可能是写下这样的东西:

class Obstacle{
public:
    // Obstacle();
    virtual bool collidesWith(double x,double y) = 0;  // = 0 makes them pure virtual
    virtual void writeMatlabDisplayCode(std::ostream &fs) = 0;
    //~Obstacle();
};

或者你可以声明一个小的do-nothing构造函数和析构函数,或者你可以使析构函数[pure]虚拟以强制派生类实现析构函数...

答案 2 :(得分:2)

类Obstacle需要一个虚拟析构函数。将析构函数定义更改为:

virtual ~Obstacle();

析构函数的定义还为具有虚函数的类创建vtable。它还确保通过基类指针删除派生类实例做正确的事。

答案 3 :(得分:0)

看起来您忘记链接包含Obstacle定义的目标文件。程序编译正确,因为它们包含原型,但在链接时,原型没有匹配的符号。