运行时的动态类型检查(RTTI,Run Time Type Indentifiation)是c++中提供的一项语言机制,它主要用于判断多态对象的具体类型。

为什么不使用c++提供的RTTI功能 

但c++中直接提供的RTTI存在一些缺点。首先它提供了取得类名(typeinfo中的name函数)的功能,这个功能实际上并不是RTTI必须的。很多时候我们不需要取得类的名字,而只是希望判断某对象的具体类型。而且typeinfo取得的名字还不一定是可移植的,不同编译器取得的类型名字不一定一样。

其次,在大多数情况下如果打开RTTI,一般来说程序中的所有多态类都会附加上RTTI信息的开销,而我们常常只需要选择其中某些类具有RTTI的功能就可以了。

总的来说,c++语言提供的RTTI与编译器相关,并不是可控的。因此我们有必要自己实现一份RTTI。

如何实现自己的RTTI?

首先需要知道如何为需要RTTI功能的类分配一个唯一的ID号。这个问题可以在STL的国际化对象Locale中找到答案。在Locale中定义了一个名为id的类,id类中没有任何成员,每一个facet类都有一个id类的静态对象。这样程序在初始化的时候会为每一个facet类中的静态id对象分配1byte的空间。这样某个facet类的静态id对象的地址就是该类的唯一标识符。      我们需要RTTI的类中也可以存放这样一个静态对象,其地址用于唯一标记每一个类。还有一个问题就是我们需要追溯一个类的所有父类。这样我们可以在每个静态ID对象其中保存其所有父类的静态ID对象的指针,这样可以构成了一棵和继承树相同的RTTI树。然后可以通过回溯的方法检查所有父类的ID。这样就可以实现自己的RTTI了。

下面是自己实现RTTI的代码:

   /**
* 运行时类型信息(Run Time Type Information).
* 用于帮助在运行中识别对象的类型.这里不使用c++本身的RTTI
* 机制是因为它并不完全可移植并且不可控.
* 注意自己实现的RTTI最多只支持MAX_BASE_CLASS_CNOUT(8)个基类.
* 因此在多重继承的时候需要注意这个限制.如果真的有一个类需
* 要继承超过8个带RTTI功能的基类,请修改MAX_BASE_CLASS_CNOUT的值,
* 并为RTTI类增加新的构造函数,然后再为指定基类数目添加一个新的
* RTTI_X_BASE_CLASS_IMPLEMENT宏.
* @author songfeiyu
*/
class RTTI
{
NON_COPYABLE_DECLARE(RTTI);
public:
/**
* 在多重继承中可以最大继承的基类的数量
* @note 一般的设计不应该超过8个吧,如果真的超过建议
* 先检查设计是否有问题...
*/
static const size_t MAX_BASE_CLASS_CNOUT = ;
/// 无基类情况下的构造函数
RTTI()
: m_baseClassCnt()
{}
/// 一个基类的情况
RTTI(const RTTI* baseClass0)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
}
/// 两个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
}
/// 三个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
}
/// 四个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2,
const RTTI* baseClass3)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
m_baseClass[] = baseClass3;
}
/// 五个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2,
const RTTI* baseClass3, const RTTI* baseClass4)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
m_baseClass[] = baseClass3;
m_baseClass[] = baseClass4;
}
/// 六个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2,
const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
m_baseClass[] = baseClass3;
m_baseClass[] = baseClass4;
m_baseClass[] = baseClass5;
}
/// 七个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2,
const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5,
const RTTI* baseClass6)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
m_baseClass[] = baseClass3;
m_baseClass[] = baseClass4;
m_baseClass[] = baseClass5;
m_baseClass[] = baseClass6;
}
/// 八个基类的情况
RTTI(const RTTI* baseClass0, const RTTI* baseClass1, const RTTI* baseClass2,
const RTTI* baseClass3, const RTTI* baseClass4, const RTTI* baseClass5,
const RTTI* baseClass6, const RTTI* baseClass7)
:m_baseClassCnt()
{
m_baseClass[] = baseClass0;
m_baseClass[] = baseClass1;
m_baseClass[] = baseClass2;
m_baseClass[] = baseClass3;
m_baseClass[] = baseClass4;
m_baseClass[] = baseClass5;
m_baseClass[] = baseClass6;
m_baseClass[] = baseClass7;
}
/// 取得基类的个数
size_t GetBaseClassCnt() const { return m_baseClassCnt; }
///取得第idx个基类指针
const RTTI* GetBaseClassRTTI(size_t idx) const { return m_baseClass[idx]; }
/**
* 判断传入的rtti指针是否与自身类型精确匹配(不检查父类).
*/
bool IsExactKindOf(const RTTI* rtti) const
{
return this == rtti;
}
/**
* 判断传入的rtti指针是否自身类型匹配(检查父类).
*/
bool IsKindOf(const RTTI* rtti) const
{
// 如果该对象的rtti和自身rtti地址一致,则类型匹配.
if(this == rtti)
{
return true;
}
// 否则就检查所有父类.
for(size_t i = ; i < rtti->GetBaseClassCnt(); ++i)
{
//如果某个父类匹配,则返回true.
if(this->IsKindOf(rtti->GetBaseClassRTTI(i)))
{
return true;
}
}
return false;
}
private:
const RTTI* m_baseClass[MAX_BASE_CLASS_CNOUT];// 基类的RTTI指针
const size_t m_baseClassCnt;// 基类的个数
}; /**
* 判断该对象是否与TYPE类型精确匹配(不检查父类).
* 用法:bool is = IsExactKindOf<TestType>(obj);
*/
template<typename TYPE, typename OBJ>
inline bool IsExactKindOf(OBJ* obj)
{
ASSERT_MESSAGE(obj, _T("The param obj is NULL."));
return TYPE::GetStaticRTTI()->IsExactKindOf(obj->GetRTTI());
}
template<typename TYPE, typename OBJ>
inline bool IsExactKindOf(const OBJ& obj)
{
ASSERT_MESSAGE(obj, _T("The param obj is NULL."));
return TYPE::GetStaticRTTI()->IsExactKindOf(obj.GetRTTI());
}
/**
* 判断该对象是否与TYPE类型匹配(检查父类).
* 用法:bool is = IsKindOf<TestType>(obj);
*/
template<typename TYPE, typename OBJ>
inline bool IsKindOf(OBJ* obj)
{
ASSERT_MESSAGE(obj, _T("The param obj is NULL."));
return TYPE::GetStaticRTTI()->IsKindOf(obj->GetRTTI());
}
template<typename TYPE, typename OBJ>
inline bool IsKindOf(const OBJ& obj)
{
return TYPE::GetStaticRTTI()->IsKindOf(obj.GetRTTI());
} /**
* 该宏用于放在所有RTTI对象的开始位置.
*/
#define RTTI_DECLARE /
public: /
static const RTTI* GetStaticRTTI() { return &ms_RTTI; } /
virtual const RTTI* GetRTTI() const { return &ms_RTTI; } /
private: /
static const RTTI ms_RTTI; /**
* 这一组宏用于定义继承n个基类的RTTI对象.
*/
#define RTTI_NO_BASE_CLASS_IMPLEMENT(className) /
const RTTI className::ms_RTTI;
#define RTTI_1_BASE_CLASS_IMPLEMENT(className, baseClass0) /
const RTTI className::ms_RTTI(baseClass0::GetStaticRTTI());
#define RTTI_2_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1) /
const RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI());
#define RTTI_3_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI());
#define RTTI_4_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, /
baseClass3) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI());
#define RTTI_5_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, /
baseClass4) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), /
baseClass4::GetStaticRTTI());
#define RTTI_6_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, /
baseClass4, baseClass5) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), /
baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI());
#define RTTI_7_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, /
baseClass4, baseClass5, baseClass6) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), /
baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI(), baseClass6::GetStaticRTTI());
#define RTTI_8_BASE_CLASS_IMPLEMENT(className, baseClass0, baseClass1, baseClass2, baseClass3, /
baseClass4, baseClass5, baseClass6, baseClass7) /
const yeo::kernel::RTTI className::ms_RTTI(baseClass0::GetStaticRTTI(), /
baseClass1::GetStaticRTTI(), baseClass2::GetStaticRTTI(), baseClass3::GetStaticRTTI(), /
baseClass4::GetStaticRTTI(), baseClass5::GetStaticRTTI(), baseClass6::GetStaticRTTI(), /
baseClass7::GetStaticRTTI());

这样只需要在需要RTTI类的声明中加上RTTI_DECLARE宏,并在实现中根据基类的数量加上对象的RTTI_X_BASE_CLASS_IMPLEMENT宏就可以了,例如:

.h file

  class A
{
RTTI_DECLARE;
public:
...
}; class B
{
RTTI_DECLARE;
public:
...
}; class C : public A,
public B
{
RTTI_DECLARE;
public:
...
};

.cpp file:

    RTTI_NO_BASE_CLASS_IMPLEMENT(A);
RTTI_NO_BASE_CLASS_IMPLEMENT(B);
RTTI_2_BASE_CLASS_IMPLEMENT(C, A, B);

这样就可以对A,B,C类的对象进行运行时的RTTI判断了。 
   注意在上面RTTI对象使用了一个固定长度的数组(8个)来保存所有直接父类的RTTI对象。这里其实可以使用多态实现对任意多数目直接父类的支持,但考虑到效率以及设计上的问题,在这里做出了8个直接父类的限制。 
   应该是用不完的,因为只要需要RTTI判断的直接父类多于8个才不支持(如果不需要对某个父类的RTTI判断可以不写进RTTI_X_BASE_CLASS_IMPLEMENT宏中,这样还可以避免不需要的查找开销,这又多了一层自我控制的选择)。

这样就可以对A,B,C类的对象进行运行时的RTTI判断了。     注意在上面RTTI对象使用了一个固定长度的数组(8个)来保存所有直接父类的RTTI对象。这里其实可以使用多态实现对任意多数目直接父类的支持,但考虑到效率以及设计上的问题,在这里做出了8个直接父类的限制。     应该是用不完的,因为只要需要RTTI判断的直接父类多于8个才不支持(如果不需要对某个父类的RTTI判断可以不写进RTTI_X_BASE_CLASS_IMPLEMENT宏中,这样还可以避免不需要的查找开销,这又多了一层自我控制的选择)。

[转]手工实现RTTI的更多相关文章

  1. RTTI(Runtime Type Information )

    RTTI 是“Runtime Type Information”的缩写,意思是:运行时类型信息.它提供了运行时确定对象类型的方法.本文将简略介绍 RTTI 的一些背景知识.描述 RTTI 的概念,并通 ...

  2. Java RTTI and Reflection

    Reference: Java编程思想 java 反射(Reflect) Java系列笔记(2) - Java RTTI和反射机制 Java Reflection in Action, 有空再补 -- ...

  3. C++ 宏、范型和RTTI 浅析

    [摘要]        RTTI(Run-Time Type Identification)是面向对象程序设计中一种重要的技术. 现行的C++标准对RTTI已经有了明白的支持. 只是在某些情况下出于特 ...

  4. Oracle 11g静默安装软件+手工创建数据库

    由于是二次跳转+远程操作,无法使用图形界面,不能直接图形界面安装.采用静默安装软件+手工创建数据库的方式完成需求. 静默模式安装Oracle软件,配置监听程序 手工建库 检查各组件是否符合要求 1. ...

  5. 学习笔记 MSSQL显错手工注入

    和朋友一起学习,速度就是快.感谢珍惜少年时. 网上很多都在长篇大论MSSQL显错手工注入,其实原理只有一小段.如下: ' and (查询一段内容)=1 and 'C'='Cnvarchar类型(查询一 ...

  6. FREEBSD手工配置网络

    在FreeBSD系统中,网络能力十分重要,对于一个标准的FreeBSD系统,至少要有一个网络界面以便与其他计算机通信.最常见的网络界面为以太网卡.此外FreeBSD也支持Token Ring和FDDI ...

  7. sql手工注入时的探测技巧汇总

    工具的灵活性肯定比不上人,在手工探测的基础上再去自定义工具,才是正道. sql注入时手工探测技巧 =================================================== ...

  8. 手工配置rsyslog配置文件详解

    手工配置 如果您无法通过脚本生成配置文件,这份指导将帮助您通过简单的复制.粘贴手动完成配置. 假定您已拥有root或sudo权限,是在通用的Linux平台使用5.8.0或更高版本的rsyslog,rs ...

  9. C 语言Struct 实现运行类型识别 RTTI

    通过RTTI,能够通过基类的指针或引用来检索其所指对象的实际类型.c++通过下面两个操作符提供RTTI. (1)typeid:返回指针或引用所指对象的实际类型.    (2)dynamic_cast: ...

随机推荐

  1. OpenERP 的XML-RPC的轻度体验+many2many,one2many,many2one创建方式

    来自:http://cn.openerp.cn/openerp_import_image_by_xmlrpc/ 每当夏秋之交,我们都有展会,展会完后,都有很多的新的潜在客户要添加,我们收了一大堆名片, ...

  2. 〖Android〗/system/etc/audio_policy.conf

    原文件注释说明: # audio hardware module section: contains descriptors for all audio hw modules present on t ...

  3. eclipse c++ 经常使用快捷键

    atl+/ //自己主动补全 ctrl+/ //凝视,或者去凝视 ctrl+shift+F //代码整理 ctrl+shift+G //跳转到调用的地方,或者,右键+Reference+Project ...

  4. Java典型应用彻查1000例:图形与网络游戏开发 PDF 扫描版[68M]

    <Java典型应用彻查1000例·图形与网络游戏开发>实例丰富,编排合理,可以让有初级Java基础的读者,从陌生到完全熟练地设计网络游戏,进而掌握3D立体绘图方法,适合作为Java网络游戏 ...

  5. 关于远程访问Oracle数据库的设置(共享数据库)

    写在前面: 需求描述:     我笔记本上安装了oracle数据库, 现在同事也想连接这个数据库. 也就是设置为别人能远程访问我本地的数据库. 思路:     通过在我笔记本WiFi共享,别人连接该W ...

  6. java测试Unicode编码以及数组的运用(初学篇)

    /*第二章第四小题*/ /* * (1)编写一个应用程序,给出汉字“你” ,“我”,“他”在Unicode 表中的位置 * (2)编写一个java应用程序,输出全部的希腊字母 */ public cl ...

  7. HDUOJ-----(1072)Nightmare(bfs)

    Nightmare Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  8. DataSnap使用UniDac处理自增长字段

    原来使用ado来访问数据库,用在DataSnap中也很方便.后来便一直使用UniDac,可发现UniDac如果用在DataSnap中要比ado麻烦很多,尤其对自增长字段.缺省值的处理上,感觉对Data ...

  9. JSEclipse—Eclipse上的JavaScript开发工具

    http://blog.csdn.net/qiaogang2003/article/details/3035056原来js开发仅仅使用ue,不过开发效率比较低下. 找到一个Eclipse下的js开发工 ...

  10. 为同一部电脑设置2个IP地址

    为同一部电脑设置2个IP地址 在HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Class\NetTrans下 点击0000.0001,000 ...