tags:

views:

220

answers:

4

Everything is fine and the final problem is so annoying. Compile is great but link fails:

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

What's the problem I have ? I can post any code you need to analyze it.

+2  A: 

Apparently you are missing and object file or library. The one which defines and declares the Obstacle object.

A good place to look for that is in the header files (*.h) files referenced in Myworld as this will give you an idea of what cpp/libraries (typically with the same name) are underlying the objects used by Myworld.

Edit, given Lisa's reply:
No, you do not need to add any *.hh files in the source code. The problem is at link-time, not compile-time.
Isn't there an Obstacle.cpp file somewhere? This would need to be compiled and the corresponding .o files would need to be added to the last gcc line in the make.

Bingo! Upon seeing Obstacle.hh
These two virtual Methods are not pure virtual, and hence the compiler expects them to be defined somewhere, somehow. And also the constructor and destructor are not defined.
The easiest would probably be to write something like:

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();
};

Alternatively you could declare a small do-nothing constructor and destructor or you could make the destructor [pure] virtual to force the derived classes to implement a destructor...

mjv
in myworld, #include "World.hh"#include "Obstacle.hh"#include "CIRCLE.hh" #include "RECTANGLE.hh" is includedis there something wrong with this since RECTANGLE and CIRCLE are sub-classes of Obstacle. should i include "CIRCLE.hh" and "RECTANGLE.hh"?
Lisa
i don't have a Obstacle.cc and the Obstacle.o because i think it's unnecessary since obstacle.hh has nothing but some virtual function and constructor
Lisa
Can you post Obstacle.hh (or relevant snippets from it)?
mjv
@ mjv i have done it
Lisa
yea, this really make sense but do these two virutal funciton related to the "typeinfo for Obstacle" error?
Lisa
A: 

It looks like you forgot to link in the object file that contains the definition of Obstacle. The programs compile correctly because they included the prototypes, but at link-time, there is no matching symbol for the prototypes.

mathepic
Obstacle is just a base class for RECANGLE and CIRCLE. so i just include "Obstacle.hh" in myworld.hh. is that ok
Lisa
It is not ok. You need real definitions.
mathepic
how can i do the real definition?
Lisa
+1  A: 

The class Obstacle needs a virtual destructor. Change the destructor definition to be:

virtual ~Obstacle();

The definition of a destructor also creates the vtable for a class with virtual functions. It also ensures that a delete of a derived class instance through a base class pointer does the right thing.

janm
+1, anyway it is vital for class with virtual methods. Another question is you need implementation.
Roman Nikitchenko
@Roman Nikitchenko: It's not _vital_ for classes with virtual methods. It's only essential if you are going to be deleting derived classes through pointers to this base class. It is a common alternative to make base class destructors protected and non-virtual.
Charles Bailey
+3  A: 

You declare a non-abstract class Obstacle, but you don't implement all its member functions.

Better declare it as abstract class:

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(){}
};

The reason is a heuristic you'll find in many C++ compilers - to avoid the needless creation of duplicate vtables and typeinfos for a class they are created when its first non-inline virtual member function (if it has one) is defined.

Your code foils this scheme: You include Obstacle.hh into some compilation unit, the compiler sees a class Obstacle that has collidesWith as first non-inline virtual member function, but it isn't defined in the current compilation unit, so the compiler thinks it can defer the creation of vtable and typeinfo for the class. Because there is no definition of collidesWith, they both end up missing when the program is linked.

hjhill
this really make sense but do these two virutal funciton related to the "typeinfo for Obstacle" error?
Lisa
edited my answer to give reasons - hope it isn't too complicated...
hjhill
thank you so much. concise and correct !
Lisa