我正在小roguelike游戏,以及用于任何目的/“东西”不是地图的一部分是基于离一个XEntity类。有几类依赖于它的,如XPlayer,XItem,和XMonster。

我的问题是,我想为指针XEntity转换为XItem当我知道一个对象是项目。我使用以拾取产品的代码示例是这样的,它是当不同的实体拾取一个项目是站在结束。

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

我首先想到的是在XEntity创建一个方法,该方法返回本身作为XItem指针,但它创建循环依赖是无法解决的。

我很为难这一个。任何帮助感激。

有帮助吗?

解决方案

如果您的知道的是,XEntity是实际工作和XItem那么你可以使用静态铸造。

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

但是,你应该检查你的设计,看看你是否能在某种程度上对实体经营这意味着,你不需要知道派生类型是。如果可以得到的基类的足够丰富的接口则可以消除该标志检查类型检查。

其他提示

铸造解决了问题,因为其他人指出:

// 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.
}

不过,我认为你前人的精力退一步,看看该程序的设计,向下转换是应该而且能够通过适当的面向对象的设计可避免的东西。一个强大的,虽然有点复杂,工具可能是 Visitor模式

我曾经相信,向下转换总是能够避免与一个“适当”的设计。这仅仅是不,虽然如此。适当的设计往往需要有一个实现新的,并不仅仅是不同行为的子对象。往往提倡的“适度”的设计会告诉你移动的新的行为了抽象的堆到它不属于的地方。并非总是如此,但如果你继续努力,以确保所有的类都可以从最抽象的点,这是非常往往在事情最终会和它只是使用的fugly

处理以集中方式向下转换一个伟大的方式是通过使用访问者模式。有几种形式访客不过,有些需要向下转型,有些则没有。非周期性游客,这确实需要向下转型的一个,更容易工作,并且,在我的经验,更强大。

另一个访问者,我已经没有试图用权利要求书,以满足与标准访问者的速度无环访问者的相同的灵活性的工作;这就是所谓的“合作访问者”。它仍然蒙上,用较快的方式与它自己的查找表,它只是这样做。我还没有尝试过合作游客的原因是,我还没有找到一种方法,使之在多higherarchies工作...但我是因为我坚持自己没有,要么花大量的时间(在我当前项目)与无环的。

有关合作访问者真正很酷的事情是返回类型。但是,我用我的专业观众参观对象的整个街区,做事情与他们。我有麻烦构想如何回报将在这些情况下工作。

在标准访问者向下转换也只是通过虚拟调用机制这样做,这是更快和有时比显式转换更安全。我不喜欢这个访客的事情是,如果你需要在窗口小部件higherarchy访问WidgetX那么你也必须实施WidgetY和WidgetZ访问()功能,即使你不关心他们。随着大和/或宽higherarchies这可能是一个PITA。其他选项不要求这一点。

还有一个“higherarchal访客”。它知道何时退出。

如果你不倾向于使用访问者,但并希望只投那么你可以考虑使用升压:: polymorphic_downcast功能。它具有动态类型转换的安全和警告机制,断言在调试版本,并在发布静态浇铸的速度。它可能不是必要的,但。有时候,你只知道你是铸造权。

这是你需要考虑一下,你想避免什么重要的事情,更是打破了LSP。如果你有一大堆的代码以“如果(小窗口>类型()== TYPE1){垂头丧气...}否则,如果(小窗口>类型()==类型2)...”,然后添加新的窗口小部件类型是影响坏的方式有很多代码是一个大问题。新的小工具会不会真的是一个小部件,因为你所有的客户端与您的higherarchy太亲密,不知道这件事。访问者模式不摆脱这个问题,但它确实集中式,这是当你有难闻的气味非常重要的,它往往可以更容易处理在它上面。

只需将其丢:

XItem* Item = (XItem*)Ent;

一个更好的方法,总体而言,是这样的:

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

为了要做到这工作,你需要启用RTTI。看这里了解更多信息。

正如已经回答,有2个操作符:

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

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

所述第二较慢但更安全(它检查是否有可能),并且可能返回null即使Ent不是

我倾向于使用两个包裹在一个方法:

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
}

这样,我得到的类型检查,同时发展(有一个例外,如果出现坏的),我得到的速度,当我完成了。您可以使用其他的策略,如果你愿意的话,但我必须承认,我很喜欢这种方式:)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top