Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I cast an object class to the interface pointer in which it implements?

I have defined an interface class like the following.

class IRecyclableObject
{
public:
    virtual ~IRecyclableObject() {}

    virtual void recycle() = 0;
    virtual void dump() = 0;
    virtual int getRecycleTypeID() = 0;
};

The following is my CharacterAI class which inherits another class and implements above interface class. It's defined as follows.

class CharacterAI : public harp::Character, public harp::IRecyclableObject
{
public:
    CharacterAI();
    virtual ~CharacterAI();

    ...

    // -- note these 3 virtual functions -- //
    virtual void recycle();
    virtual void dump();
    virtual int getRecycleTypeID();

    ...
};

Those three virtual functions as defined in interface, I have implemented it normally in CharacterAI class. Nothing fancy goes there.

It's time when I put them into use with ObjectPool (a self-made) class in which the data storage of available objects in

m_freeList

uses CCArray class.

The problem occurs in the following code.

IRecyclableObject* ObjectPool::popFreeObjectAndAddToActiveListForType(int recycleTypeID)
{
    // search from free-list
    for(unsigned int i=0; i<m_freeList->count(); i++)
    {
        IRecyclableObject* obj = (IRecyclableObject*)m_freeList->objectAtIndex(i);
        CharacterAI *obj1 = (CharacterAI*)m_freeList->objectAtIndex(i);

        CCLog("recycleTypeID : %d %d %d", obj->getRecycleTypeID(), recycleTypeID, obj1->getRecycleTypeID());

        ...
    }
    return NULL;
}

The expected result is to show

recycleTypeID : 4 4 4

But I got

recycleTypeID : 524241408 4 4

The first one is clearly garbage there and randomly different from each loop. I tried to put a breakpoint in the implemented function getRecycleTypeID() inside CharacterAI class before it returns. I found out that only

obj1->getRecycleTypeID()

was called but not another.

By focusing on obj variable, It's clearly seen that it seems different object calls that function, and the cause may come from casting an object to interface class and use if from there in which it's wrong or some kind.

What's going on there? Can I cast an object type class to interface class pointer (which it implements) and correctly call functions as defined in interface class?

like image 953
haxpor Avatar asked Feb 17 '13 16:02

haxpor


1 Answers

Can I cast an object class to the interface pointer in which it implements?

Yes. But that's not your case. Function objectAtIndex() returns a pointer to a CCObject, and that class definitely does not implement the IRecyclableObject interface.

Thus, a brutal C-style cast of CCObject* to IRecyclableObject* will result in reinterpreting the layout of an object of the former type as if it was an object of the latter type. That's bad, and leads to Undefined Behavior.

You should use dynamic_cast<> to cast your CCobject* to a IRecyclableObject*:

IRecyclableObject* obj = dynamic_cast<IRecyclableObject*>(
    m_freeList->objectAtIndex(i)
    );

Notice, however, that this is not even needed if you just want your pointer to be eventually cast to an object of type CharacterAI. Just directly cast it to that type:

CharacterAI* obj = dynamic_cast<CharacterAI*>(m_freeList->objectAtIndex(i));

dynamic_cast<> returns a null pointer if the run-time type of the object pointed to by the pointer you are trying to cast is not (equal to or derived from) the target type of the downcast. Therefore, in those cases where you are not sure about the concrete type of the pointed object, don't forget to check whether the returned pointer is non-null before dereferencing it.

like image 200
Andy Prowl Avatar answered Oct 04 '22 02:10

Andy Prowl