C++ – Invalid ESP when using multiple inheritance in C++ (VS2005)

cmultiple-inheritancestack-pointervisual-studio-2005

I've been making a game which uses the Box2D physics engine, and I've come across some weirdness with the stack pointer (ESP) and multiple inheritance. I've managed to reproduce it in a minimal amount of code, and it seems that the order in which I declare the classes to be used in multiple inheritance seems to dictate whether the program crashes or not.

#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;
}

Running this in debug mode causes the following error

Run-Time Check Failure #0 – The value
of ESP was not properly saved across a
function call. This is usually a
result of calling a function declared
with one calling convention with a
function pointer declared with a
different calling convention.

When I step in to the following line of code:

physZone->Collide(otherZone, 10, 1);

I notice it's going into CScoreZone::OnAttach, not CScoreZone::Collide. Why is this? WHen I change the order of inheritance for CScoreZone, it works fine

class CScorezone : public IPhysicsObject, public IBoardFeature

I'm running on VS2005 SP2 (8.0.50727.768) on Windows XP. Any ideas?

Best Answer

You don't have to assign CScorezone* to void* and then cast it to IPhysicsObject*. Since CScorezone is-a IPhysicsObject you can simply assign to base pointer:

    IPhysicsObject *scoreZone = new CScorezone();
    IPhysicsObject *otherZone = new CScorezone();

You're also missing public virtual destructor in IPhysicsObject declaration.

Edit:

I a callback situation as you describe in the comments (going through some C api?) I'd use simple struct with a pointer to polymorphic type to avoid undefined casts, something like:

    // 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( ... );
    }
Related Topic