一切都很好,最后的问题很烦人。编译很棒,但链接失败:
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
我有什么问题?我可以发布您需要的任何代码来分析它。
答案 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定义的目标文件。程序编译正确,因为它们包含原型,但在链接时,原型没有匹配的符号。