5

次のようなインターフェイス クラスを定義しました。

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

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

以下は、別のクラスを継承し、上記のインターフェイス クラスを実装する私のCharacterAIクラスです。以下のように定義されています。

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();

    ...
};

インターフェイスで定義されているこれら 3 つの仮想関数は、CharacterAIクラスで通常どおり実装しました。そこには派手なものは何もありません。

利用可能なオブジェクトのデータ ストレージが含まれるObjectPool (自作) クラスでそれらを使用する時が来ました。

m_freeList

CCArrayクラスを使用します。

問題は、次のコードで発生します。

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

期待される結果は、

recycleTypeID : 4 4 4

しかし、私は得ました

recycleTypeID : 524241408 4 4

最初のものは明らかにガベージであり、各ループとはランダムに異なります。CharacterAIクラス内の実装関数getRecycleTypeID()が戻る前に、ブレークポイントを配置しようとしました。それだけだとわかった

obj1->getRecycleTypeID()

呼ばれましたが、別のものではありませんでした。

obj変数に焦点を当てると、別のオブジェクトがその関数を呼び出しているように見え、その原因はオブジェクトをインターフェイス クラスにキャストし、そこから if を使用することが原因である可能性があることが明確にわかります。

何が起こっているのですか?オブジェクト型クラスをインターフェイス クラス ポインター (それが実装する) にキャストし、インターフェイス クラスで定義されている関数を正しく呼び出すことはできますか?

4

1 に答える 1

9

オブジェクト クラスを、それが実装されているインターフェイス ポインターにキャストできますか?

はい。しかし、それはあなたの場合ではありません。関数objectAtIndex()は へのポインターを返しますが、CCObjectそのクラスは間違いなくインターフェイスを実装していません。IRecyclableObject

CCObject*したがって、 toの残忍な C スタイルのキャストはIRecyclableObject*、前者の型のオブジェクトのレイアウトを後者の型のオブジェクトであるかのように再解釈することになります。それは悪いことであり、 Undefined Behaviorにつながります。

dynamic_cast<>あなたをにキャストするCCobject*ために使用する必要がありますIRecyclableObject*

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

ただし、ポインターを最終的に type のオブジェクトにキャストするだけの場合は、これは必要ないことに注意してくださいCharacterAI。その型に直接キャストするだけです:

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

dynamic_cast<>キャストしようとしているポインターが指すオブジェクトの実行時の型が、ダウンキャストのターゲット型ではない (等しいか派生した) 場合、null ポインターを返します。したがって、指定されたオブジェクトの具体的な型がわからない場合は、逆参照する前に、返されたポインターが null でないかどうかを確認することを忘れないでください。

于 2013-02-17T17:11:09.743 に答える