2

Possible Duplicate:
GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'

I'm doing a little project in C++ and I've come into some problems regarding virtual functions.

I have a base class with some virtual functions:

#ifndef COLLISIONSHAPE_H_
#define COLLISIONSHAPE_H_


namespace domino
{
class CollisionShape : public DominoItem
{
public:
// CONSTRUCTOR
//-------------------------------------------------

// SETTERS
//-------------------------------------------------

// GETTERS
//-------------------------------------------------

    virtual void GetRadius() = 0;
    virtual void GetPosition() = 0;
    virtual void GetGrowth(CollisionShape* other) = 0;
    virtual void GetSceneNode();

// OTHER
//-------------------------------------------------

    virtual bool overlaps(CollisionShape* shape) = 0;

};
}

#endif /* COLLISIONSHAPE_H_ */

and a SphereShape class which extends CollisionShape and implements the methods above

/* SphereShape.h */

#ifndef SPHERESHAPE_H_
#define SPHERESHAPE_H_

#include "CollisionShape.h"

namespace domino
{
class SphereShape : public CollisionShape
{

public:
// CONSTRUCTOR
//-------------------------------------------------
    SphereShape();
    SphereShape(CollisionShape* shape1, CollisionShape* shape2);

// DESTRUCTOR
//-------------------------------------------------

    ~SphereShape();

// SETTERS
//-------------------------------------------------
    void SetPosition();
    void SetRadius();

// GETTERS
//-------------------------------------------------

    void GetRadius();
    void GetPosition();
    void GetSceneNode();
    void GetGrowth(CollisionShape* other);

// OTHER
//-------------------------------------------------

    bool overlaps(CollisionShape* shape);
};
}

#endif /* SPHERESHAPE_H_ */

and the .cpp file:

/*SphereShape.cpp*/
 #include "SphereShape.h"

#define max(a,b) (a>b?a:b)

namespace domino
{

// CONSTRUCTOR
//-------------------------------------------------

SphereShape::SphereShape(CollisionShape* shape1, CollisionShape* shape2)
{
}

// DESTRUCTOR
//-------------------------------------------------

SphereShape::~SphereShape()
{
}

// SETTERS
//-------------------------------------------------

void SphereShape::SetPosition()
{
}

void SphereShape::SetRadius()   
{
}

// GETTERS
//-------------------------------------------------

void SphereShape::GetRadius()   
{

}

void SphereShape::GetPosition()   
{  
}


void SphereShape::GetSceneNode()
{
}

void SphereShape::GetGrowth(CollisionShape* other)
{
}

// OTHER
//-------------------------------------------------

bool SphereShape::overlaps(CollisionShape* shape)
{
     return true;
}

}

These classes, along some other get compiled into a shared library.

Building libdomino.so
g++ -m32 -lpthread -ldl -L/usr/X11R6/lib -lglut -lGLU -lGL -shared     -lSDKUtil  -lglut  -lGLEW  -lOpenCL   -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86  -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/TempSDKUtil/lib/x86 -L"/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86"   -lSDKUtil  -lglut  -lGLEW  -lOpenCL -o build/debug/x86/libdomino.so build/debug/x86//Material.o build/debug/x86//Body.o build/debug/x86//SphereShape.o build/debug/x86//World.o build/debug/x86//Engine.o build/debug/x86//BVHNode.o

When I compile the code that uses this library I get the following error:

../../../lib/x86//libdomino.so: undefined reference to `vtable for domino::CollisionShape'
../../../lib/x86//libdomino.so: undefined reference to `typeinfo for domino::CollisionShape'

Command used to compile the demo that uses the library:

g++ -o build/debug/x86/startdemo build/debug/x86//CMesh.o build/debug/x86//CSceneNode.o build/debug/x86//OFF.o build/debug/x86//Light.o build/debug/x86//main.o build/debug/x86//Camera.o -m32 -lpthread -ldl -L/usr/X11R6/lib -lglut -lGLU -lGL  -lSDKUtil  -lglut  -lGLEW  -ldomino  -lSDKUtil  -lOpenCL   -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86  -L/home/adrian/AMD-APP-SDK-v2.4-lnx32/TempSDKUtil/lib/x86  -L../../../lib/x86/ -L"/home/adrian/AMD-APP-SDK-v2.4-lnx32/lib/x86" 

(the -ldomino flag)

And when I run the demo, I manually tell it about the library:

LD_LIBRARY_PATH=../../lib/x86/:$AMDAPPSDKROOT/lib/x86:$LD_LIBRARY_PATH bin/x86/startdemo 

After reading a bit about virtual functions and virtual tables I understood that virtual tables are handled by the compiler and I shouldn't worry about it, so I'm a little bit confused on how to handle this issue.

I'm using gcc version 4.6.0 20110530 (Red Hat 4.6.0-9) (GCC)

Later edit: I'm really sorry, but I wrote the code by hand directly here. I have defined the return types in the code. I apologize to the 2 people that answered below.

I have to mention that I am a beginner at using more complex project layouts in C++.By this I mean more complex makefiles, shared libraries, stuff like that.


My problem was caused by the fact that I didn't define the body of virtual void CollisionShape::GetSceneNode().

The way to fix this is to either define the above function, or declare it as pure virtual as such:

virtual void CollisionShape::GetSceneNode() = 0;
Community
  • 1
  • 1
adivasile
  • 2,377
  • 3
  • 24
  • 32
  • @adivasile: please post a minimal snippet that compiles and shows the problem. When you went to fix the problem of not having return types you reversed the types returned by the functions. Sometimes it's hard to diagnose errors when there are red herrings that have nothing to do with the real scenario. Please also give the command line for the code that uses the library, since that's where you see the error. – Michael Burr Jun 26 '11 at 00:33
  • @Michael Burr: I added the code used to link the library.As for the snippet, I'm not sure I can provide since there are quite a lot of files and dependencies involved. – adivasile Jun 26 '11 at 00:45
  • 1
    As posted, your code is asking for trouble. `CollisionShape` needs a virtual destructor. Perhaps you declared it, but forgot to define? It's hard to tell having a non-compilable snippet. – n. m. could be an AI Jun 26 '11 at 01:08
  • It is close to being compilable. Replace return types with `void`, remove irrelevant includes and function bodies, and that's it. – n. m. could be an AI Jun 26 '11 at 01:13
  • Ok, I added the full definitions for both classes, and removed return types, and includes.Let me know if I missed anything. – adivasile Jun 26 '11 at 01:27
  • Yes, there's `GetSceneNode` virtual function – n. m. could be an AI Jun 26 '11 at 01:53
  • Yes, there's `CollisionShape::GetSceneNode` virtual function, declared but not defined. This is one typical reason of the undefined vtable error. Either implement it or make it pure virtual. – n. m. could be an AI Jun 26 '11 at 01:59
  • There's also a `SphereShape:GetSceneNode()` defined in SphereShape.cpp. – adivasile Jun 26 '11 at 02:02
  • -1 apparently not the real code – Cheers and hth. - Alf Jun 26 '11 at 02:17
  • -1: asking others to debug code that doesn't actually exist. – sarnold Jun 26 '11 at 02:23
  • `SphereShape::GetSceneNode()` is **not** `CollisionShape::GetSceneNode()`. You need to define the latter. Note that the code still won't compile as the two functions have different return types. The `DominoItem` class is missing too.Please check your snippets with an actual compiler before posting. – n. m. could be an AI Jun 26 '11 at 02:26
  • Ok, now I see what you mean.I added `=0` to the virtual declaration of `GetSceneNode`.I actually meant it to be pure virtual.I apologize for the inconsistencies in my code.I really haven't used inexistent code, I just missed some return types when I edited it. If you will post an answer, I will gladly award it to you. – adivasile Jun 26 '11 at 02:34

4 Answers4

3

Any non-pure virtual function must be defined, even if it's never used. A missing definition will often result in the 'vtable undefined' linker error, especially when the very first non-pure, non-inline virtual function of a class is left undefined. In your case, CollisionShape::GetSceneNode() is left undefined.

On an unrelated note, every class that has a virtual function needs a virtual destructor, every time, absolutely no exceptions whatsoever. The language unfortunately doesn't enforce this, so it's your responsibility. G++ has a flag, -Weffc++, which enables warnings for this and other common pitfalls, described in the Scott Meyers's book "Effective C++". I strongly recommend using this flag all the time. Using -Werror by default is also a good habit. Suppress individual warnings one by one, and only if there's no possibility to fix the code.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • -1 "every class that has a virtual function needs a virtual destructor". As a a counter example, the COM `IUnknown` interface has three pure virtual functions and it does not have a virtual destructor. If you have a Windows machine then you're using quite a lot of software that in turn uses thousands of classes derived from that class, and you can multiply that by the number of Windows machines: apparently it works just fine. – Cheers and hth. - Alf Jun 26 '11 at 23:58
  • The COM interfaces rely on a `Release` mechanism that negates the effect of not having a virtual destructor. That is, since you'd never call `delete` on a `IUnknown`, the virtual destructor behaviour is not required. In most cases you'd be interested in supporting `delete` being used on some interface pointer, so generally a virtual destructor is required. – Pooven Dec 08 '14 at 20:43
1

I can't say for certain whether this will fix your compilation error, but in any case you need to declare a virtual destructor (virtual ~CollisionShape()) in your CollisionShape class. Failure to do so will result in undefined runtime behavior when SphereShape is deleted through its base class pointer (a pointer to CollisionShape). Of course, since a virtual constructor is indeed added to a class's vtbl, I guess it's not beyond the realm of possibility that this is the culprit behind your error.

In Effective C++, Scott Meyers has the following to say.

The C++ language standard is unusually clear on this topic. When you try to delete a derived class object through a base class pointer and the base class has a nonvirtual destructor [...], the results are undefined. That means compilers may generate code to do whatever they like: reformat your disk, send suggestive mail to your boss, fax source code to your competitors, whatever. (What often happens at runtimme is that the derived class's destructor is never called. [...])

Chris Frederick
  • 5,482
  • 3
  • 36
  • 44
  • Thanks for your answer, but I have already identified the issue with the help of n.m..I didn't implement `CollisionShape::GetSceneNode()`, nor did I declare it as pure virtual. – adivasile Jun 26 '11 at 02:59
  • @adivasile Glad to hear you solved your problem! To prevent more people from trying to respond to your question (and to help others who may have the same one), please post your answer here and accept it. As I said, though, you still need a virtual destructor *even if your code compiles*. – Chris Frederick Jun 26 '11 at 03:03
-1

Due to the conflicting declarations of GetSceneNode, in your current code

virtual void GetSceneNode();

in the base class, and

SceneNode* GetSceneNode();

in the derived class, your code should not compile. You should not get to the linking stage. I'm pretty sure that the code that you're presenting is not your real code.

Hence, I downvoted the question.

But regarding the error that you evidently produced with some other code, it has been asked before on SO, and answered for example here.

Hence, I also voted to close the question.

Cheers & hth.,

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • the definitions in the source code are correct.both have SceneNode* as a return type.When I removed the return types to make the snippet compilable, I overlooked that declaration and I apologize.Since I have specified that the library compiles, you should have realized that it wasn't the problem. – adivasile Jun 26 '11 at 02:23
  • Exactly what criteria do you propose that people should apply to understand which parts of what you say are correct, and which are incorrect? – Cheers and hth. - Alf Jun 26 '11 at 03:11
-2

This may not be the whole problem, but you are missing a return type on those functions. ie

virtual double GetPosition() = 0;
rtn
  • 127,556
  • 20
  • 111
  • 121
Leon
  • 1,141
  • 13
  • 25