Published by orzz.org(). (https://orzz.org/%e4%b8%80%e4%b8%aa%e7%ae%80%e5%8d%95%e7%9a%84rtti%e5%ae%9e%e7%8e%b0/)
RTTI是"Runtime Type Information"的缩写,意思是:运行时类型信息.它提供了运行时确定对象类型的方法.
最近在写的一些东西,不想使用MFC之类的框架,但是却在很多地方需要根据名称确定指针的转换类型或者利用抽象工厂生产抽象的类对象指针...
我很不喜欢不容易维护且难看的"switch case",而C++本身的RTTI功能又显得很单薄...干脆自己写一个简单的实现好了.
下面的实现参考了MFC的RTTI机制,因为它的方法本身也不复杂,而且使用上也比较简单.
RTTI.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
////////////////////////////////////////////////////////////////// // RTTI - RTTI 支持 // // Author: 木头云 // Blog: http://darkc.at // E-Mail: memleak@darkc.at // Version: 1.0.1001.1823 ////////////////////////////////////////////////////////////////// #ifndef __STDCPX_RTTI_H__ #define __STDCPX_RTTI_H__ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 ////////////////////////////////////////////////////////////////// // RTTI 起始类声明 class CBaseObj; ////////////////////////////////////////////////////////////////// // type_id 自增量 extern int TypeInfoOrder; // 类型信息结构 struct TypeInfo { typedef CBaseObj* (*pfn_dc)(GCAlloc& gc); LPTSTR className; int type_id; TypeInfo* pBaseClass; pfn_dc m_pfnCreateObject; // NULL => abstract class CBaseObj* CreateObject(GCAlloc& gc) { if( m_pfnCreateObject == NULL ) return NULL; return (*m_pfnCreateObject)(gc); } bool operator == (const TypeInfo& info) { return this == &info; } bool operator != (const TypeInfo& info) { return this != &info; } }; ////////////////////////////////////////////////////////////////// // 向工厂注册 TypeInfo 指针 #define REGISTER_TYPEINFO(key, inf) CTypeInfoFactory::GetInstance()->RegisterTypeInfo(key, inf) // 从工厂得到 TypeInfo 指针 #define GET_TYPEINFO(key) CTypeInfoFactory::GetInstance()->GetTypeInfo(key) // TypeInfo 指针单例工厂 class CTypeInfoFactory sealed { private: typedef Map<tstring, TypeInfo*> key_map; private: key_map dc_funcs; private: CTypeInfoFactory(GCAlloc& gc) : dc_funcs(gc) {} public: // 获得工厂单例 static CTypeInfoFactory* GetInstance() { // 仅用于RTTI时不需要考虑线程同步问题 // 为了提高效率, 此处不加线程同步锁 static GCAlloc gc; static CTypeInfoFactory instance(gc); return &instance; } // 向工厂注册一个类名 bool RegisterTypeInfo(LPCTSTR c_key, TypeInfo* inf) { if( c_key == NULL ) return false; tstring key(c_key); if( dc_funcs.find(key) == dc_funcs.end() ) { dc_funcs.insert( key_map::value_type(key, inf) ); return true; } else return false; } // 从工厂获得一个 TypeInfo TypeInfo* GetTypeInfo(LPCTSTR c_key) { if( c_key == NULL ) return NULL; tstring key(c_key); if( dc_funcs.find(key) == dc_funcs.end() ) return NULL; else return dc_funcs[key]; } }; ////////////////////////////////////////////////////////////////// // Base Typedef 宏定义 #define DEF_BASETYPE(base_name) public: typedef base_name Base; ////////////////////////////////////////////////////////////////// // TYPEINFO 类型信息宏定义 #define TYPEINFO_OF_CLS(cls_name) (cls_name::GetTypeInfoClass()) #define TYPEINFO_OF_OBJ(obj_name) (obj_name.GetTypeInfo()) #define TYPEINFO_OF_PTR(ptr_name) (ptr_name->GetTypeInfo()) #define TYPEINFO_MEMBER(cls_name) rttiTypeInfo ////////////////////////////////////////////////////////////////// // 类的 RTTI 宏定义 #define DECLARE_TYPEINFO_CLS(cls_name, base_name) DEF_BASETYPE(base_name) public: virtual int GetTypeID() { return TYPEINFO_MEMBER(cls_name).type_id; } virtual LPCTSTR GetTypeName() { return TYPEINFO_MEMBER(cls_name).className; } virtual TypeInfo& GetTypeInfo() { return TYPEINFO_MEMBER(cls_name); } static TypeInfo& GetTypeInfoClass() { return TYPEINFO_MEMBER(cls_name); } private: static TypeInfo TYPEINFO_MEMBER(cls_name); #define DECLARE_TYPEINFO_NULL(cls_name) public: virtual int GetTypeID() { return TYPEINFO_MEMBER(cls_name).type_id; } virtual LPCTSTR GetTypeName() { return TYPEINFO_MEMBER(cls_name).className; } virtual TypeInfo& GetTypeInfo() { return TYPEINFO_MEMBER(cls_name); } static TypeInfo& GetTypeInfoClass() { return TYPEINFO_MEMBER(cls_name); } private: static TypeInfo TYPEINFO_MEMBER(cls_name); public: bool IsKindOf(TypeInfo& cls); // dynamically typeinfo #define DECLARE_DYNAMIC_CLS(cls_name, base_name) DECLARE_TYPEINFO_CLS(cls_name, base_name) #define DECLARE_DYNAMIC_NULL(cls_name) DECLARE_TYPEINFO_NULL(cls_name) // dynamically constructable #define DECLARE_DYNCREATE_CLS(cls_name, base_name) DECLARE_DYNAMIC_CLS(cls_name, base_name) public: static CBaseObj* CreateObject(GCAlloc& gc); private: static bool m_bRegSuccess; #define DECLARE_DYNCREATE_NULL(cls_name) DECLARE_DYNAMIC_NULL(cls_name) public: static CBaseObj* CreateObject(GCAlloc& gc); private: static bool m_bRegSuccess; ///////////////////////////////// #define IMPLEMENT_TYPEINFO_CLS(cls_name, base_name, pfn_new) TypeInfo cls_name::TYPEINFO_MEMBER(cls_name) = { _T(#cls_name), TypeInfoOrder++, &(base_name::GetTypeInfoClass()), pfn_new }; #define IMPLEMENT_TYPEINFO_NULL(cls_name, pfn_new) TypeInfo cls_name::TYPEINFO_MEMBER(cls_name) = { _T(#cls_name), TypeInfoOrder++, NULL, pfn_new }; bool cls_name::IsKindOf(TypeInfo& cls) { TypeInfo* p = &(this->GetTypeInfo()); while( p != NULL ) { if( p->type_id == cls.type_id ) return true; p = p->pBaseClass; } return false; } // dynamically typeinfo #define IMPLEMENT_DYNAMIC_CLS(cls_name, base_name) IMPLEMENT_TYPEINFO_CLS(cls_name, base_name, NULL) #define IMPLEMENT_DYNAMIC_NULL(cls_name) IMPLEMENT_TYPEINFO_NULL(cls_name, NULL) // dynamically constructable #define IMPLEMENT_DYNCREATE_CLS(cls_name, base_name) IMPLEMENT_TYPEINFO_CLS(cls_name, base_name, cls_name::CreateObject) CBaseObj* cls_name::CreateObject(GCAlloc& gc) { return /*new cls_name*/GC_NEW(gc, cls_name); } bool cls_name::m_bRegSuccess = REGISTER_TYPEINFO( _T(#cls_name), &(cls_name::TYPEINFO_MEMBER(cls_name)) ); #define IMPLEMENT_DYNCREATE_NULL(cls_name) IMPLEMENT_TYPEINFO_NULL(cls_name, cls_name::CreateObject) CBaseObj* cls_name::CreateObject(GCAlloc& gc) { return /*new cls_name*/GC_NEW(gc, cls_name); } bool cls_name::m_bRegSuccess = REGISTER_TYPEINFO( _T(#cls_name), &(cls_name::TYPEINFO_MEMBER(cls_name)) ); ////////////////////////////////////////////////////////////////// // 动态指针转换宏定义 #define DYNAMIC_CAST(cls_name, object_ptr) dynamic_cast_t<cls_name>( TYPEINFO_OF_CLS(cls_name), object_ptr ) // 动态对象创建宏定义 #define DYNAMIC_CREATE(cls_name, key, gc) dynamic_create_t<cls_name>( key, gc ) ////////////////////////////////////////////////////////////////// // RTTI 起始类 class CBaseObj { DECLARE_DYNCREATE_NULL(CBaseObj) }; ////////////////////////////////////////////////////////////////// // 动态指针转换函数模板 template <class T> inline T* dynamic_cast_t(TypeInfo& cls, CBaseObj* ptr) { if( ptr ) return ptr->IsKindOf(cls) ? (T*)ptr : NULL; else return NULL; } // 动态对象创建函数 template <class T> inline T* dynamic_create_t(LPCTSTR c_key, GCAlloc& gc) { if( c_key == NULL ) return NULL; TypeInfo* inf = GET_TYPEINFO(c_key); if( inf ) return DYNAMIC_CAST( T, inf->CreateObject(gc) ); else return NULL; } ////////////////////////////////////////////////////////////////// #endif // __STDCPX_RTTI_H__ |
RTTI.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "stdafx.h" #ifndef __STDCPX_RTTI_H__ #include "detailRTTI.h" #endif ////////////////////////////////////////////////////////////////// // type_id 自增量初始化 extern int TypeInfoOrder = 0; // CBaseObj 成员定义 IMPLEMENT_DYNCREATE_NULL(CBaseObj) |
在"struct TypeInfo"中我用到了许式伟的StdExt库,若要单独使用的话需要把"Map"改为"map",使用stl的map完成同样的功能,并删除掉带有"GCAlloc"的语句.
此RTTI在使用上类似MFC的RTTI,所有需要用到RTTI功能的类必须继承自"class CBaseObj".
使用示例:
Show.h
1 2 3 4 5 6 7 8 |
class CShow : public CBaseObj { DECLARE_DYNAMIC_CLS(CShow, CBaseObj) public: CShow() {} virtual ~CShow() {} }; |
Show.cpp:
1 |
IMPLEMENT_DYNAMIC_CLS(CShow, CBaseObj) |