C ++:识别对象的类型

时间:2011-06-22 15:37:39

标签: c++ c++11

我很好奇当前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,其派生类型为EntityStateStandingState等。类DeadState是仅需要通用Entity对象的类型class EntityState需要准确知道实体所处的状态,以决定是否绘制“常备”动画或“死”动画,或其他任何内容。


编辑:当然,如果可能的话,我想以这样一种方式实现游戏,即使实体表示也不需要知道实体状态的类型。如果有办法做到这一点,那我就用它。 :)我将调查访客模式。

9 个答案:

答案 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. 添加一个提供绘制所需信息的功能
  2. 使用双重调度机制
  3. 最简单的解决方案可能是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。您可以使用它们来确定对象是否从类继承。

相关问题