[英]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.