我很好奇当前C ++和C ++ 11中可用的构造或语言特性可用于推断对象的类型。一个例子:
class Base {
};
class DerivA
: public Base {
};
class DerivB
: public Base {
};
void foo(Base* obj) {
// Identify if `obj` is a `DerivA` or a `DerivB`
}
这是过于简单化了。看起来似乎没有办法识别类型,最好的解决方案是为两个派生类型提供函数的重载,并取消基类。
我的真实用例是一个类对对象的确切类型不感兴趣(即只需要Base
的实现)而另一个类需要确切知道{{1}的实现第一个类正在使用。
这发生在基于组件的游戏实体系统中。基数为Base
,其派生类型为EntityState
,StandingState
等。类DeadState
是仅需要通用Entity
对象的类型class EntityState
需要准确知道实体所处的状态,以决定是否绘制“常备”动画或“死”动画,或其他任何内容。
编辑:当然,如果可能的话,我想以这样一种方式实现游戏,即使实体表示也不需要知道实体状态的类型。如果有办法做到这一点,那我就用它。 :)我将调查访客模式。
答案 0 :(得分:6)
您可以使用dynamic_cast
:
if(DerivA * derivA = dynamic_cast<DerivA*>(obj)){
// it is a DerivA
}
答案 1 :(得分:3)
两种方式:
如果您的课程是多态的,dynamic_cast
或者您可以使用typeid
使用typeid
#include <typeinfo.h>
typeid(YourClass).name()
使用dynamic_cast
DerivA& dynamic_cast<DerivA&> (object);
DerivA* dynamic_cast<DerivA*> (object);
Base类中必须至少有一个虚函数才能使dynamic_cast工作,否则会出现编译错误。
如果您尝试转换为指向不是实际对象类型的类型的指针,则转换的结果将为NULL。对于类似情况,在引用的情况下,强制转换将抛出bad_cast
异常。
答案 2 :(得分:1)
查看标准库的<typeinfo>
部分(例如see here。)
答案 3 :(得分:1)
您可以使用dynamic_cast
来标识派生类对象的类型。例如,执行:DerivedA* p = dynamic_cast<Derived*>(pBase);
如果满足p!=NULL
条件,则其DerivedA
类型的对象。
答案 4 :(得分:1)
您可以使用visitor pattern解决上一段中描述的问题。你试过吗?它甚至可以在不知道其操作类型的情况下解决问题。
答案 5 :(得分:1)
与大多数建议相反,我不会直接使用RTTI(typeinfo或dynamic_cast)。你可以做不同的事情:
最简单的解决方案可能是1),只需添加一个虚拟方法,告诉您对象处于什么状态,并使用它来确定如何为对象设置动画。这种方法的问题在于它需要为每个需要它的东西添加State类:动画,声音,运动计算......
使用像访问者模式这样的双重调度形式将复杂性从State层次结构移动到访问者层次结构中,该层次结构必须包含每个不同状态(在所有级别)的重载。应用程序中的模型将更简单,但使用该模型将变得更加麻烦。
答案 6 :(得分:0)
假设您的类型中包含虚拟方法,可以使用C ++的实时类型识别(RTTI)与dynamic_cast和typeid
之类的东西但是,更好的设计可能是实现虚拟方法来完全隐藏类型。例如:
class EntityState {
virtual void Draw( Entity entity ) = 0;
}
class DeadState : EntityState {
virtual void Draw( Entity entity ) {
//*** render the entity as dead
}
}
class AliveState : EntityState {
virtual void Draw( Entity entity ) {
//*** render the entity as alive!
}
}
class Entity {
EntityState myEntityState;
void Draw() {
myEntityState.Draw( this );
}
}
现在可以将您的实体绘制为死或活,没有任何if-then-else或switch语句代码,如果您突然想要将新状态添加到您的实体中,则需要更新。
答案 7 :(得分:0)
通常比尝试查询对象类型更好的选择是向基类添加虚函数:
class Base { public: virtual int Animation() const=0; };
class DerivA : public Base { public: int Animation() const { return 0; } };
class DerivB : public Base { public: int Animation() const { return 1; } };
然后让所有不同的动画由一个整数标识,可能有一个不可修改的动画数组:
Animation anim1, anim2, anim3;
Animation *array[5] = { &anim1, &anim2, &anim3 };
void foo(Base *b) {
int animnum = b->Animation();
Animation *anim = array[animnum];
...
}
至少有一种方法可以让它正常工作。
答案 8 :(得分:-1)
对于继承,我会研究static_cast和dynamic_cast。您可以使用它们来确定对象是否从类继承。