我有一个游戏对象的层次结构:
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< GameObject *>中。并成功调用虚拟方法,如更新和绘图,这一切都很好。但有时我需要检测我正在处理的GameObject类型。对于这种情况,我们提出了一个解决方案: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?
答案 0 :(得分:2)
为什么不对draw
和update
函数进行模板设置,以便传入任何T
,而不是拥有大量的继承类链,它将为您提供所需的一切。如果您需要为特定T
设置不同的行为,则可以专攻。
只是一个建议。
答案 1 :(得分:1)
您可以使用dynamic_cast
。
if ( dynamic_cast<Building*>(obj) )
{
// then do stuff
}
不需要enum
或getType()
方法。
答案 2 :(得分:0)
我的直觉是你需要知道他们在运行时键入的内容然后可能是设计有问题。如果你在对象上调用“Do stuff”,那么使用虚函数和多态就意味着你不需要知道对象是什么。
但是,如果您启用了RTTI,那么这似乎是一种在运行时确定对象类型的方法,而无需将它们添加到基类中。
typeid
可用于确定运行时的类型。
答案 3 :(得分:0)
使用dynamic_cast: http://msdn.microsoft.com/en-us/library/cby9kycs%28v=VS.80%29.aspx
您可以在链接中找到一些示例。