C ++虚函数。问题与vtable

时间:2011-06-25 23:55:08

标签: c++ virtual-functions vtable typeinfo

  

可能重复:
  GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'

我正在用C ++做一个小项目,我遇到了一些关于虚函数的问题。

我有一个带有一些虚函数的基类:

#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_ */

SphereShape类扩展CollisionShape并实现上述方法

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

和.cpp文件:

/*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;
}

}

这些类与其他类一起编译成共享库。

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

当我编译使用此库的代码时,我收到以下错误:

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

用于编译使用该库的演示的命令:

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" 

-ldomino标志)

当我运行演示时,我手动告诉它库:

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

在阅读了一些关于虚函数和虚拟表的内容之后,我明白虚拟表是由编译器处理的,我不应该担心它,所以我对如何处理这个问题感到有些困惑。

我正在使用gcc version 4.6.0 20110530 (Red Hat 4.6.0-9) (GCC)

稍后编辑: 我真的很抱歉,但是我直接在这里写了代码。 我在代码中定义了返回类型。 我向下面回答的2个人道歉。

我必须提到我是在C ++中使用更复杂的项目布局的初学者。我的意思是更复杂的makefile,共享库,这样的东西。


我的问题是由于我没有定义virtual void CollisionShape::GetSceneNode()的主体。

解决这个问题的方法是定义上面的函数,或者将它声明为纯虚函数:

virtual void CollisionShape::GetSceneNode() = 0;

4 个答案:

答案 0 :(得分:3)

必须定义任何非纯虚函数,即使它从未使用过。缺少定义通常会导致'vtable undefined'链接器错误,尤其是当类的第一个非纯非内联虚函数未定义时。在您的情况下,CollisionShape::GetSceneNode()未定义。

在一个不相关的说明中,每个具有虚函数的类都需要一个虚析构函数,每次都绝对没有例外。遗憾的是,这种语言没有强制执行,所以这是你的责任。 G ++有一个标志-Weffc++,它可以为这个和其他常见的陷阱提供警告,如Scott Meyers的书“Effective C ++”中所述。我强烈建议一直使用这个标志。默认情况下使用-Werror也是一个好习惯。逐个抑制个别警告,并且只有在无法修复代码的情况下才会出现。

答案 1 :(得分:1)

我无法确定这是否会解决您的编译错误,但无论如何您需要在virtual ~CollisionShape()中声明虚拟析构函数(CollisionShape)类。如果通过其基类指针(指向SphereShape的指针)删除CollisionShape,则无法执行此操作将导致未定义的运行时行为。当然,由于虚拟构造函数确实被添加到类的vtbl中,我想这并不是可能的范围,这是你的错误背后的罪魁祸首。

在Effective C ++中,Scott Meyers有以下几点要说。

  

C ++语言标准在这个主题上异常清晰。当您尝试通过基类指针删除派生类对象并且基类具有非虚拟析构函数[...]时,结果是未定义的。这意味着编译器可以生成代码来执行他们喜欢的任务:重新格式化磁盘,向老板发送暗示性邮件,将源代码传真给竞争对手,等等。 (在runtimme中经常发生的是派生类的析构函数永远不会被调用。[...]

答案 2 :(得分:-1)

由于GetSceneNode的声明存在冲突,在您当前的代码中

virtual void GetSceneNode();
基类中的

SceneNode* GetSceneNode();

在派生类中,您的代码不应该编译。你不应该进入连接阶段。我很确定你所呈现的代码不是真正的代码。

因此,我对这个问题进行了低估。

但是关于您使用其他代码明显产生的错误,之前已经问过SO,并回答了例如here

因此,我也投票决定结束这个问题。

干杯&第h。,

答案 3 :(得分:-2)

这可能不是整个问题,但是您缺少这些函数的返回类型。即

virtual double GetPosition() = 0;