C++:识别对象的类型
C++: Identifying the type of the object
我很好奇当前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
的实现),而另一个类需要确切地知道第一个类使用的是Base
的实现。
这种情况发生在基于组件的游戏实体系统中。基础为EntityState
,其派生类型为StandingState
、DeadState
等。类Entity
只需要一个通用的EntityState
对象,类EntityRepresentation
需要确切地知道实体处于什么状态,以决定是绘制"站立"动画还是绘制"死亡"动画,或其他什么。
编辑:当然,如果可能的话,我希望以这样一种方式实现游戏,即使实体表示也不需要知道实体状态的类型。如果有办法做到这一点,那么我会使用它。:)我会研究访问者模式。
您可以使用dynamic_cast
:
if(DerivA * derivA = dynamic_cast<DerivA*>(obj)){
// it is a DerivA
}
两种方式:
如果你的类是多态使用,dynamic_cast
或者您可以使用typeid
typeid的用法
#include <typeinfo.h>
typeid(YourClass).name()
dynamic_cast
的使用
DerivA& dynamic_cast<DerivA&> (object);
DerivA* dynamic_cast<DerivA*> (object);
基类中必须至少有一个虚拟函数才能使dynamic_cast工作,否则将出现编译错误。
如果试图强制转换指向一个不是实际对象类型的类型的指针,则强制转换的结果将为NULL。对于引用的类似情况,强制转换将抛出bad_cast
异常。
查看标准库的<typeinfo>
部分(例如,请参阅此处)
您可以使用dynamic_cast
来标识派生类对象的类型。例如,当执行:DerivedA* p = dynamic_cast<Derived*>(pBase);
时,如果满足p!=NULL
条件,则它是DerivedA
类型的对象。
您在上一段中描述的问题可以使用访问者模式来解决。你试过了吗?它甚至可以在不知道其操作类型的情况下解决问题。
与大多数建议相反,我不会直接使用RTTI(typeinfo或dynamic_cast)。你可以做不同的事情:
- 添加提供绘制所需信息的函数
- 使用双重调度机制
最简单的解决方案可能是1),只需添加一个虚拟方法,告诉你对象处于什么状态,并使用它来确定如何设置对象的动画。这种方法的问题是,它需要为每一个需要它的东西向State类添加方法:动画、声音、运动计算。。。
使用类似访问者模式的双重调度形式将复杂性从State层次结构转移到访问者层次结构中,访问者层次结构必须包含每个不同State(在所有级别)的重载。应用程序中的模型将更简单,但该模型的使用将变得更加繁琐。
假设你的类型中有一个虚拟方法,你可以使用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语句代码,如果您突然希望将新状态添加到实体中,则需要更新这些代码。
通常比查询对象类型更好的选择是向基类中添加一个虚拟函数:
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];
...
}
这至少是让它正常工作的一种方法。
对于继承性,我将研究static_cast和dynamic_cast。您可以使用这些来确定对象是否是从类继承的。
- std::unordered_map 类型对象声明期间出现"field has incomplete type"错误
- C++ 多态模板类,模板类型对象的实例化
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- 如何构造一个 std::variant 类型对象,其自身 Templated 和构造函数转发参数
- C++:初始化指向具有不同类型对象的指针数组
- 在类 C++ 中构造的模板类型对象
- 如何将颁发者名称设置为x509_req类型对象
- 将任何数据类型/对象作为参数传递以确定其大小
- 将引用类型对象的数组从C#封送到C++
- <T> 从类型对象创建类型<T1>对象的构造函数
- C++是否有现有的方法来检查对象是否是派生类型对象
- C 模板:创建与现有对象相同的类型对象
- 链接列表中的虚函数 - 多种返回类型(对象)
- 没有适当操作员()的类型对象的呼叫
- 制作垫子类型对象的数组.输出窗口显示同一帧
- 抽象类型对象的分配
- 在std::list中就地创建自定义类型对象
- 接受泛型列表类型对象的参数
- C++-将模板类型对象强制转换为特定的数据类型
- 试图在C++中打印存储在类型对象数组中的信息