[英]Invalid ESP when using multiple inheritance in C++ (VS2005)
我一直在制作一款使用Box2D物理引擎的游戏,而且我遇到了一些堆栈指针(ESP)和多重继承的奇怪现象。 我已经设法用最少量的代码重现它,似乎我声明要在多重继承中使用的类的顺序似乎决定了程序是否崩溃。
#include <iostream>
#include <string.h>
using namespace std;
class IPhysicsObject
{
public:
virtual void Collide(IPhysicsObject *other, float angle, int pos)=0;
};
class IBoardFeature
{
public:
IBoardFeature(){};
~IBoardFeature(){};
virtual bool OnAttach(int x){ return true; }
virtual bool Update(int x, float dt)=0;
};
/*
class CScorezone : public IBoardFeature, public IPhysicsObject // this breaks !!!
class CScorezone : public IPhysicsObject, public IBoardFeature // this works !!!
*/
class CScorezone : public IBoardFeature, public IPhysicsObject
{
public:
CScorezone(){}
~CScorezone(void){}
virtual bool Update(int x, float dt)
{
return true;
}
virtual void Collide(IPhysicsObject *other, float angle, int pos)
{
}
virtual bool OnAttach(int x){ return true; }
};
int main(int argc, char *argv[])
{
CScorezone *scoreZone = new CScorezone();
CScorezone *otherZone = new CScorezone();
void *voidZone = scoreZone;
IPhysicsObject *physZone = static_cast<IPhysicsObject*>(voidZone);
physZone->Collide(otherZone, 10, 1);
delete scoreZone;
delete otherZone;
// wait for user input
int x;
cin >> x;
return 0;
}
在调试模式下运行此操作会导致以下错误
运行时检查失败#0 - ESP的值未在函数调用中正确保存。 这通常是调用使用一个调用约定声明的函数和使用不同调用约定声明的函数指针的结果。
当我介入以下代码行时:
physZone->Collide(otherZone, 10, 1);
我注意到它进入了CScoreZone :: OnAttach,而不是CScoreZone :: Collide。 为什么是这样? 当我改变CScoreZone的继承顺序时,它工作正常
class CScorezone : public IPhysicsObject, public IBoardFeature
我在Windows XP上运行VS2005 SP2(8.0.50727.768)。 有任何想法吗?
您不必将CScorezone*
指定为void*
,然后将其转换为IPhysicsObject*
。 由于CScorezone
是一个 IPhysicsObject
你可以简单地分配给基指针:
IPhysicsObject *scoreZone = new CScorezone();
IPhysicsObject *otherZone = new CScorezone();
您还在IPhysicsObject
声明中缺少公共虚拟析构函数。
我在评论中描述了一个回调情况(通过一些C api?)我会使用带有指向多态类型的指针的简单struct
来避免未定义的强制转换,例如:
// one more level of indirection
struct cb_data
{
IPhysicsObject* target;
};
// callback function
int callback( void* data )
{
const cb_data& cbd( *static_cast<cb_data*>( data ));
return cbd.target->Collide( ... );
}
问题是你先将指针强制转换为void *。 编译器不知道如何对指针执行静态转换。 如果使用多重继承来使用第二个超类虚拟表,则需要在强制转换期间更改指针值。 在使用static_cast之前,只需将指针强制转换回CScoreZone *即可。
好吧,在你的代码中,你似乎故意通过使用void *
作为转换中的中间类型来破坏分层转换的完整性。 ScoreZone *
首先转换为void *
然后转换为IPhysicsObject *
。 你得到的结果是未定义的行为。
你为什么做这个? 你期望会发生什么?
尼古拉告诉你如何在给出你的例子的情况下首先避免施放。 但是,如果您确实需要进行类型转换,则在使用对象时始终使用dynamic_cast,它会执行运行时类型检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.