C++虚拟函数.vtable的问题
C++ virtual functions.Problem with vtable
可能重复:
GCC C++链接器错误:对';vtable for XXX';,未定义对';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_ */
以及扩展CCD_ 2并实现上述方法的CCD_
/* 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)
稍后编辑:我真的很抱歉,但我直接在这里手写了代码。我已经在代码中定义了返回类型。我向下面回答的两个人道歉。
我必须提到,我是C++中使用更复杂项目布局的初学者。我指的是更复杂的makefile、共享库之类的东西。
我的问题是因为我没有定义virtual void CollisionShape::GetSceneNode()
的主体。
解决这个问题的方法是定义上述函数,或者将其声明为纯虚拟函数:
virtual void CollisionShape::GetSceneNode() = 0;
任何非纯虚拟函数都必须定义,即使从未使用过。缺少定义通常会导致"vtable undefined"链接器错误,尤其是当类的第一个非纯、非内联虚拟函数未定义时。在您的情况下,CollisionShape::GetSceneNode()
未定义。
与此无关的是,每个具有虚拟函数的类都需要一个虚拟析构函数,每次都绝对没有例外。不幸的是,语言并没有强制执行这一点,所以这是你的责任。G++有一个标志-Weffc++
,它可以对这个和其他常见的陷阱发出警告,正如Scott Meyers的书《有效的C++》中所描述的那样。我强烈建议您始终使用此标志。默认情况下使用-Werror也是一个好习惯。逐个取消单个警告,并且仅在无法修复代码的情况下。
我不能确定这是否会修复编译错误,但在任何情况下,您都需要在CollisionShape
类中声明一个虚拟析构函数(virtual ~CollisionShape()
)。如果不这样做,当通过其基类指针(指向SphereShape
1的指针)删除SphereShape
时,将导致未定义的运行时行为。当然,由于一个虚拟构造函数确实被添加到了类的vtbl
中,我想这并不是错误的罪魁祸首。
在Effective C++中,Scott Meyers有以下几点要说。
C++语言标准在这个主题上异常清晰。当您试图通过基类指针删除派生类对象,并且基类具有非虚拟析构函数[…]时,结果是未定义的。这意味着编译器可以生成代码来做他们喜欢做的任何事情:重新格式化磁盘,向老板发送建议性邮件,将源代码传真给竞争对手,等等。(在runtime中经常发生的事情是,派生类的析构函数从未被调用。〔…〕)
由于GetSceneNode
的声明冲突,在您当前的代码中
virtual void GetSceneNode();
在基类中,以及
SceneNode* GetSceneNode();
在派生类中,代码不应编译。你不应该进入链接阶段。我非常确信您所呈现的代码不是您真正的代码。
因此,我否决了这个问题。
但是,关于您显然在其他代码中产生的错误,以前在SO上有人问过它,例如在这里得到了回答。
因此,我也投票决定结束这个问题。
干杯&hth。,
这可能不是全部问题,但这些函数缺少返回类型。即
virtual double GetPosition() = 0;
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- C++ 继承问题:未定义对"vtable"的引用
- OpenGL与C++:将类数组传递给glTexImage2d时出现vtable问题
- C++虚拟函数.vtable的问题
- 对vtable的未定义引用;虚拟功能问题
- 具有相同名称的多个类导致vtable问题