C++虚函数。vtable 问题
可能的重复:
GCC C++ 链接器错误:未定义的引用“XXX 的 vtable”,对“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_ */
以及一个扩展了 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 类:
/*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;
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
任何非纯虚函数都必须被定义,即使它从未被使用过。缺少定义通常会导致“vtable undefined”链接器错误,特别是当类的第一个非纯、非内联虚拟函数未定义时。在您的情况下,
CollisionShape::GetSceneNode()
未定义。与此无关的是,每个具有虚函数的类每次都需要一个虚析构函数,绝对没有例外。不幸的是,语言并没有强制执行这一点,所以这是你的责任。 G++ 有一个标志
-Weffc++
,它可以针对此问题和其他常见陷阱发出警告,这在 Scott Meyers 的书“Effective C++”中进行了描述。我强烈建议一直使用这个标志。默认使用-Werror也是一个好习惯。仅当无法修复代码时才一一抑制各个警告。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.我不能肯定地说这是否会修复您的编译错误,但无论如何您都需要在您的 <代码>CollisionShape 类。如果不这样做,当通过其基类指针(指向 CollisionShape 的指针)删除 SphereShape 时,将导致未定义的运行时行为。当然,由于虚拟构造函数确实被添加到类的
vtbl
中,所以我想这也有可能是错误背后的罪魁祸首。在《Effective C++》中,Scott Meyers 有以下说法。
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 yourCollisionShape
class. Failure to do so will result in undefined runtime behavior whenSphereShape
is deleted through its base class pointer (a pointer toCollisionShape
). Of course, since a virtual constructor is indeed added to a class'svtbl
, 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.
由于
GetSceneNode
的声明存在冲突,因此在基类和
派生类中的当前代码中,您的代码不应编译。您不应该进入链接阶段。我很确定您提供的代码不是您真正的代码。
因此,我否决了这个问题。
但是关于您显然用其他代码产生的错误,之前已经有人问过它,并回答了例如 这里。
因此,我也投票结束这个问题。
干杯&呵呵,
Due to the conflicting declarations of
GetSceneNode
, in your current codein the base class, and
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.,
这可能不是全部问题,但您缺少这些函数的返回类型。 IE
This may not be the whole problem, but you are missing a return type on those functions. ie