문제

I'm working on a small roguelike game, and for any object/"thing" that is not a part of the map is based off an XEntity class. There are several classes that depend on it, such as XPlayer, XItem, and XMonster.

My problem is, that I want to convert a pointer from XEntity to XItem when I know that an object is in item. The sample code I am using to pick up an item is this, it is when a different entity picks up an item it is standing over.

void XEntity::PickupItem()
{
    XEntity *Ent = MapList; // Start of a linked list

    while(true)
    {
        if(Ent == NULL) { break; }

        if(Ent->Flags & ENT_ITEM)
        {
            Ent->RemoveEntity(); // Unlink from the map's linked list

            XItem *Item = Ent // Problem is here, type-safety

            // Code to link into inventory is here

            break;
        }

        Ent = Ent->MapList;
    }
}

My first thought was to create a method in XEntity that returns itself as an XItem pointer, but it creates circular dependencies that are unresolvable.

I'm pretty stumped about this one. Any help is greatly appreciated.

도움이 되었습니까?

해결책

If you know that the XEntity is actuall and XItem then you can use a static cast.

XItem* Item = static_cast<XItem *>(Ent);

However, you should review you design and see if you can operate on the entity in a way that means that you don't need to know what derived type it is. If you can give the base class a sufficiently rich interface you may be able eliminate the flag check type inspection.

다른 팁

Casting solves the problem as others have pointed out:

// dynamic_cast validates that the cast is possible. It requires RTTI 
// (runtime type identification) to work. It will return NULL if the 
// cast is not possible.
XItem* Item = dynamic_cast<XItem*>(Ent);
if(Item)
{
    // Do whatever you want with the Item.
}
else
{
    // Possibly error handling code as Ent is not an Item.
}

However I think that you sould step back and look at the design of the program, as downcasting is something that should and can be avoided by a proper object-oriented design. One powerful, even though a bit complex, tool might be the Visitor pattern.

키트!당신은 지금 앞에 재해 복구 계획을 세우고, 지금을 찾고 있지 않아야합니다!그러나 그것은 새로운 서버로 마이그레이션하는 단계를 따르고 있습니다.

새 서버로 SharePoint 이동

Microsoft의 공식 라인은이 패치를 제거하고 다시 설치하는 것입니다. LIVE를 적용하기 전에 테스트 서버에서 항상 테스트 서버에서 패치를 테스트하는 것입니다.

복구 된 후에 재해 복구 계획을 찾는 데 시간을 보내십시오.

Just cast it:

XItem* Item = (XItem*)Ent;

A better approach, overall, is this:

if (XItem *Item = dynamic_cast<XItem*>(Ent)) {
    Ent->RemoveEntity();

    // Code to link into inventory is here

    break;
}
XItem * Item = dynamic_cast< XItem * >( Ent );

if ( Item )
    // do something with item

In order for that to work, you need to enable RTTI. Look here for more information.

As have been answered, there are 2 operators:

XItem* Item = static_cast<XItem*>(Ent);

And:

XItem* Item = dynamic_cast<XItem*>(Ent);

the second is slower but safer (it checks if it's possible) and might return null even if Ent is not.

I tend to use both wrapped in a method:

template <class T, class U>
T* my_cast(U* item)
{
#ifdef _NDEBUG_
  if (item) return &dynamic_cast<T&>(*item); // throw std::bad_cast
  else return 0;
#else
  return static_cast<T*>(item);
#endif
}

This way I get type checking while development (with an exception if something goes bad) and I get speed when I'm finished. You can use other strategies if you wish, but I must admit I quite like this way :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top