C++ 我该怎么处理这个奇怪的错误呢?

C++ 我该怎么处理这个奇怪的错误呢?,c++,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:

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

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**
障碍物


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

显然您丢失了对象文件或库。定义和声明障碍物对象的对象

在Myworld中引用的头文件*.h文件中可以找到一个很好的位置,因为这将让您了解Myworld使用的对象的底层通常是哪些具有相同名称的cpp/库

编辑,根据Lisa的回复: 不,您不需要在源代码中添加任何*.hh文件。问题出在链接时,而不是编译时。 某处没有障碍物.cpp文件吗?这需要编译,相应的.o文件需要添加到make中的最后一行gcc中

宾果!看到障碍物时 这两个虚拟方法不是纯虚拟的,因此编译器希望它们以某种方式被定义在某个地方。而且构造函数和析构函数也没有定义。 最简单的方法可能是写以下内容:


或者,您可以声明一个小型的不做任何事情的构造函数和析构函数,或者您可以使析构函数[纯]为虚拟的,以强制派生类实现析构函数…

显然,您缺少对象文件或库。定义和声明障碍物对象的对象

在Myworld中引用的头文件*.h文件中可以找到一个很好的位置,因为这将让您了解Myworld使用的对象的底层通常是哪些具有相同名称的cpp/库

编辑,根据Lisa的回复: 不,您不需要在源代码中添加任何*.hh文件。问题出在链接时,而不是编译时。 某处没有障碍物.cpp文件吗?这需要编译,相应的.o文件需要添加到make中的最后一行gcc中

宾果!看到障碍物时 这两个虚拟方法不是纯虚拟的,因此编译器希望它们以某种方式被定义在某个地方。而且构造函数和析构函数也没有定义。 最简单的方法可能是写以下内容:


或者,您可以声明一个小型的不做任何事情的构造函数和析构函数,或者您可以使析构函数[pure]为虚拟的,以强制派生类实现析构函数…

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

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

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

virtual ~Obstacle();

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

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

virtual ~Obstacle();

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

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

最好将其声明为抽象类:

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和Type in FIX,如果定义了一个非内联虚成员函数,则


您的代码挫败了这一方案:您在某个编译单元中包含了barriend.hh,编译器会看到一个类障碍,它与第一个非内联虚拟成员函数发生了冲突,但它没有在当前编译单元中定义,因此编译器认为它可以推迟创建该类的vtable和typeinfo。因为没有collidesWith的定义,所以当程序链接时,它们都会丢失。

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

最好将其声明为抽象类:

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和Type in FIX,如果定义了一个非内联虚成员函数,则

您的代码挫败了这个方案:您将障碍物.hh包含到某个编译单元中,编译器会看到一个类障碍物,它与第一个非内联虚拟成员函数发生冲突,但它没有在当前编译单元中定义,因此编译器认为它可以延迟

为类创建vtable和typeinfo。因为没有collidesWith的定义,所以当程序链接时,它们都会丢失。

是否有障碍物类,如果有,哪些源文件有其成员函数的定义?重复?是的,类障碍是具有两个子类圆形和矩形的基类。他们都有两个共同的虚拟世界functions@Amro,ye,我再次询问,因为我尝试了他们提供的一些方法,但错误仍然存在。请发布包含障碍类定义的文件的代码以及定义障碍成员函数的源文件。您是否有障碍类,如果是,哪些源文件有其成员函数的定义?重复?是的,类障碍是具有两个子类圆形和矩形的基类。他们都有两个共同的虚拟世界functions@Amro,ye,我再次询问,因为我尝试了他们提供的一些方法,但错误仍然存在。请发布包含障碍物类定义的文件的代码,以及定义障碍物成员函数的源文件。在myworld中,include World.hh include barrier.hh include CIRCLE.hh include RECTANGLE.hh包含是否有问题,因为矩形和圆是障碍的子类。我应该包括CIRCLE.hh和RECTANGLE.hh吗?我没有障碍物.cc和障碍物.o,因为我认为这是不必要的,因为障碍物.hh只有一些虚拟函数和构造函数,或者你可以发布障碍物.hh或其相关片段吗?是的,这确实有道理,但这两个虚拟函数是否与障碍错误的类型信息相关?在myworld中,include World.hh include birder.hh include CIRCLE.hh include RECTANGLE.hh被包括在内是否有问题,因为矩形和圆是障碍的子类。我应该包括CIRCLE.hh和RECTANGLE.hh吗?我没有障碍物.cc和障碍物.o,因为我认为这是不必要的,因为障碍物.hh只有一些虚拟函数和构造函数,或者你可以发布障碍物.hh或其相关片段吗?是的,这确实有道理,但这两个虚拟函数是否与障碍错误的typeinfo相关?障碍只是RECANGLE和CIRCLE的基类。所以我只在myworld.hh中包含障碍。好吧,不好。你需要真正的定义。我怎么做真正的定义?障碍只是一个基础类的重角和圆。所以我只在myworld.hh中包含障碍。好吧,不好。你需要真正的定义。我怎样才能做真正的定义?+1,不管怎样,这对于使用虚拟方法的类来说是至关重要的。另一个问题是您需要实现。@Roman Nikitchenko:这对于具有虚拟方法的类来说并不重要。只有当您要通过指向这个基类的指针删除派生类时,这才是必要的。使基类析构函数受保护且非虚拟是一种常见的替代方法。+1,无论如何,对于具有虚拟方法的类来说是至关重要的。另一个问题是您需要实现。@Roman Nikitchenko:这对于具有虚拟方法的类来说并不重要。只有当您要通过指向这个基类的指针删除派生类时,这才是必要的。使基类析构函数受保护且非虚拟是一种常见的替代方法。