以NiObject作为根节点的Gamebryo对象使用单继承的方式编写。这样NiObject的子类形成了一个类型树(注意这是类型之间的关系树不是指对象实例之间的关系)。运行时类型信息(RTTI)系统使得应用程序可以快速判断任何NiObject或其子类的直接类型或祖先类型
RTTI支持三个基本的操作:
1.判断一个对象的是不是严格的指定类型
2.判断一个对象是不是一个指定类型的派生类
3.动态转换一个类对象的指针到派生类的指针
所有的NiObject 派生类必须使用NiDeclareRTTI宏来定义静态RTTI 数据成员。 用来在运行时刻检测类类型。要实现动态类型识别非常简单,只需类似如下操作
因为c++开启运行时刻类型识别是非常浪费效率的行为,不是一个商业程序应该做的。而很多库都提供了自己的类型识别。Gamebryo 也提供了这样一个快速的
类型检测类型。几乎所有的类都是从其派生的
// NiNewClass.h
class NiNewClass : public NiAVObject
{
NiDeclareRTTI;
// <other stuff>
};
// NiNewClass.cpp
NiImplementRTTI(NiNewClass, NiAVObject);
常用函数:
NiIsKindOf 判断类对象是否是一个类型或者该类型的父类型
NiIsExactKindOf 判断一个类对象是否为某种类型。但不包含其父类型
NiDynamicCast 动态转换一个类为其原类型或者父类型
示例:
NiNode* pkNode = NiNew NiNode;
bool bResult;
bResult = NiIsExactKindOf(NiNode, pkNode); // bResult is true
bResult = NiIsExactKindOf(NiAVObject, pkNode); // bResult is false
bResult = NiIsKindOf(NiAVObject, pkNode); // bResult is true
bResult = NiIsKindOf(NiSwitchNode, pkNode); // bResult is false
NiObject* pkObject = pkNode;
NiAVObject* pkDynAVObj = NiDynamicCast(NiAVObject, pkObject); // pkDynAVObj == pkNode
NiNode* pkDynNode = NiDynamicCast(NiNode, pkObject); // pkDynNode == pkNode
NiSwitchNode* pkDynSw = NiDynamicCast(NiSwitchNode, pkObject); // pkDynSw == 0
bool bResult;
bResult = NiIsExactKindOf(NiNode, pkNode); // bResult is true
bResult = NiIsExactKindOf(NiAVObject, pkNode); // bResult is false
bResult = NiIsKindOf(NiAVObject, pkNode); // bResult is true
bResult = NiIsKindOf(NiSwitchNode, pkNode); // bResult is false
NiObject* pkObject = pkNode;
NiAVObject* pkDynAVObj = NiDynamicCast(NiAVObject, pkObject); // pkDynAVObj == pkNode
NiNode* pkDynNode = NiDynamicCast(NiNode, pkObject); // pkDynNode == pkNode
NiSwitchNode* pkDynSw = NiDynamicCast(NiSwitchNode, pkObject); // pkDynSw == 0
应该避免类似下面的代码:
void Function(NiAVObject* pkObject)
{
if (NiIsKindOf(NiNode, pkObject))
{
NiNode* pkNode = NiDynamicCast(NiNode, pkObject);
// do something with pkNode
}
}
NiDynamicCast 判断转换是否安全实质上重复了NiIsKindOf的工作。在NiIsKingOf已经判断对象是确定的类型时,静态转换到这个类型就是安全的。上面函数更好的写法如下:
void Function(NiAVObject* pkObject)
{
if (NiIsKindOf(NiNode, pkObject))
{
NiNode* pkNode = (NiNode*) pkObject;
// do something with pkNode
}
}
The following code shows how NiObject is set up and how derived classes are set up.
// NiObject.h
class NiObject : public NiRefObject
{
NiDeclareRootRTTI(NiObject);
// <other NiObject stuff goes here>
};
// NiObject.cpp
NiImplementRootRTTI(NiObject);
// NiObjectNET.h
class NiObjectNET : public NiObject
{
NiDeclareRTTI;
// <other NiObjectNET stuff goes here>
};
// NiObjectNET.cpp
NiImplementRTTI(NiObjectNET, NiObject);
// NiAVObject.h
class NiAVObject : public NiObjectNET
{
NiDeclareRTTI;
// <other stuff>
};
// NiAVObject.cpp
NiImplementRTTI(NiAVObject, NiObjectNET);