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

1

5

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?

Gasholder answered 17/2, 2013 at 16:55 Comment(14)
What type is returned by m_freeList->objectAtIndex()?Antitrust
@AndyProwl It's CCObject*.Gasholder
How does CharacterAI inherit from CCObject, through harp::Character?Antitrust
Ditto to what Andy just asked.Playwright
Are there other virtual functions in the omitted part of CharacterAI?Ducan
@AndyProwl Yes, CharacterAI -> Character -> CCSprite -> CCObject at the end.Gasholder
@haxpor: That's the problem then. Will write an answer.Antitrust
what and how are you storing in m_freeList?Substation
@MinLin yes, there's another one virtual function there.Gasholder
Does Character perhaps also inherit from IRecyclableObject?Bobbibobbie
@MariusBancila I store pre-initialized objects there before this function calls. Just go through the loop and store it one by one.Gasholder
I don't like the cast to IRecyclableObject *, it shouldn't be needed as the object is of a class derived from it (in such asignments C++ does some adjust-the-pointer-to-the-right-offset dance IIRC).Thistledown
@Bobbibobbie No, only CharacterAI that inherits IRecyclableObject.Gasholder
@Thistledown ObjectPool will work with any class that implements IRecyclableObject, I want it to be generic as much as possible.Gasholder
A
9

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.

Antitrust answered 17/2, 2013 at 17:11 Comment(1)
That solved my problem, and thanks to make me pay more attention to dynamic_cast, and other casting type not just c-style cast. It's about RTTI and runtime I'm dealing with it in this problem. Now I figure my own part of problem in other codes. Thanks!Gasholder

© 2022 - 2024 — McMap. All rights reserved.