【问题标题】:Object type detection in hierarchy层次结构中的对象类型检测
【发布时间】:2012-02-07 13:46:31
【问题描述】:

我有一个游戏对象的层次结构:

class GameObject {
public:
    virtual void update(float dt) = 0;
    virtual void draw() = 0;
};
class Building : public GameObject {}
class Sawmill : public Building {}
class Human : public GameObject {}

等等。所有对象都由游戏管理(它不是 GameObject 的子类:)。游戏将所有对象存储在std::vector中,并成功调用update、draw等虚方法,这样就好了。但有时我需要检测我正在处理的游戏对象类型。对于这种情况,我们提出了一个解决方案:GameObject 有一个 GameObject 类型的枚举,每个 GameObject 子类都从这个枚举中返回自己的值。

class GameObject {
public:
    enum GOType
    {
        GOGameObject,
        GOBuilding,
        GOSawmill,
        GOHuman,
        ...
    }
    static GOType Type() { return GOGameObject; }
    virtual GOType getType() const { return GameObject::Type(); }
};

class Building : public GameObject {
public:
    static GOType Type() { return GOBuilding; }
    virtual GOType getType() const { return Building::Type(); }
};

因此,GameObject 的每个子类都有自己的“静态 GOType Type()”方法版本,该方法从枚举 GOType 中返回一个值。它重载了虚拟方法“GOType getType() const”,它只是调用它自己的类方法 Type()。在游戏中的任何地方,我都可以检查我指向的对象是否是建筑物:

if (obj && obj->getType() == Building::Type()) {
    // then do stuff
}

为了清楚起见——这个解决方案运行良好,并且已经证明自己是可扩展的并且非常高效(我们提出的第一个解决方案是在 getType() 中返回字符串并比较它们;它非常慢)。

我看到的唯一缺点是每次添加新的 GameObject 子类时都必须在 GameObject 中扩展 GOType。现在它包含了大约一百种类型,而且看起来和感觉都不漂亮(我在这里是个完美主义者:)

所以,我的问题是:是否有任何其他解决方案与此问题一样有效,但无需在 GameObject 中扩展 GOType?

【问题讨论】:

  • // then do stuff 中有什么内容?根据这一点,您可以获得更好的解决方案。 (antiifcampaign.com)
  • “有时我需要检测我正在处理的游戏对象的类型” - 这可能是您设计中的错误。如果您经常检查类型,那么尽管使用了类,但您并没有以面向对象的方式进行编程。要对不同类型做出不同的反应,请使用double dispatching
  • 非常相似的问题在这里:stackoverflow.com/questions/6123042/…
  • @TamásSzelei 相信我,使用枚举来检测实际对象类型是该项目中最漂亮的设计解决方案之一 :) 其他一切都要糟糕得多。顺便说一句,谢谢你的链接,我去看看

标签: c++ oop hierarchy


【解决方案1】:

与其拥有大量的继承类,不如将drawupdate 函数模板化,这样你就可以传入任何T,它会做你需要的任何事情。如果您需要针对特定​​的T 有不同的行为,您可以专门化。

只是一个建议。

【讨论】:

  • 没有完全理解你的意思。你能提供一些代码来说明你的意思吗?
【解决方案2】:

您可以使用dynamic_cast

if ( dynamic_cast<Building*>(obj) ) 
{
    // then do stuff
}

不需要enumgetType() 方法。

【讨论】:

  • @Firedragon:好像任何人都愚蠢到可以在缺少核心语言功能的情况下编译他们的代码。
  • @DeadMG - 由于某些历史原因,我们在项目中不使用 RTTI - dimayak 32 分钟前
【解决方案3】:

使用 dynamic_cast: http://msdn.microsoft.com/en-us/library/cby9kycs%28v=VS.80%29.aspx

您可以在链接中找到一些示例。

【讨论】:

    【解决方案4】:

    我的直觉是,您需要知道他们在运行时键入的内容,然后可能是设计存在问题。如果您在对象上调用“Do stuff”,那么使用虚函数和多态意味着您不需要知道对象是什么。

    但这就是说,如果您启用了 RTTI,那么这似乎是一种在运行时确定对象类型的方法,而无需将它们的类型添加到基类中。

    typeid 可用于在运行时确定类型。

    【讨论】:

    • 由于一些历史原因,我们在项目中没有使用RTTI
    • @dimayak 如果没有 RTTI,您将无法使用 dynamic_casttypeid,因此我怀疑在运行时检测需要您在代码中使用它的方式(除非比我更有知识的人可以提出一种方法) 但正如我和其他人所说,有一些方法可以使用多态性,所以你不需要知道类型是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-28
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    相关资源
    最近更新 更多