RTTI(Run-Time Type Identification),通過運行時類型信息程序能夠使用基類的指針或引用來檢查這些指針或引用所指的對象的實際派生類型。
C++ 裡通過虛函數增加額外信息的方法實現了RTTI。GCC和VS的實現也大同小異,並且都有專門的設置來開關來禁止或使用RTTI。
和RTTI相關操作的函數是typeid和dynamic_cast.
這裡將結合前面的內容,自己實現一個RTTI。
1.定義
1 namespace blog { 2 class Object; 3 class Type 4 { 5 public: 6 struct Rtti 7 { 8 public: 9 typedef const Rtti& (*TypeId)(void); 10 public: 11 Rtti( 12 const Type* baseType, 13 const char *pname, 14 long long hash, 15 Object* (*constructor)() = nullptr 16 ); 17 Object* newObject()const; 18 const Type* Id()const; 19 const char* getName()const; 20 long long getHash()const; 21 const Type* getBaseTypes()const { return _baseType; } 22 23 bool isExactKindOf(const Type& type) const; 24 bool isKindOf(const Type& baseRtti) const; 25 26 private: 27 const Type* _baseType; 28 const char* _name; 29 long long _hash; 30 Object* (*_constructor)(); 31 }; 32 public: 33 Type(); 34 Type(const Rtti::TypeId type); 35 bool operator == (Type type)const; 36 bool operator != (Type type)const; 37 const char* getName()const; 38 long long getHash()const; 39 Object* newObject()const; 40 41 bool isKindOf(Type id)const; 42 bool isExactKindOf(Type id)const; 43 const Type* getBaseTypes()const; 44 45 typedef Rtti::TypeId ID; 46 const static Type vNone; 47 private: 48 Rtti::TypeId _typeid; 49 }; 50 }
其中Object是將實現RTTI的類,Type是封裝類的TypeId,其中的struct Rtti將保存類的基本信息
下面定義Object基礎類以及其派生類
1 class Object : public Memory 2 { 3 private: 4 static Object* New() { return new Object(); } 5 friend class Type; 6 public: 7 static const Type::Rtti& TypeId() 8 { 9 const static Type rtti[] = { nullptr }; 10 const static Type::Rtti inst(rtti, "Object", "Object"_hash, New); 11 return inst; 12 } 13 virtual Type getType()const { return TypeId; } 14 }; 15 class DerivedObject : public Object 16 { 17 private: 18 static Object* New() { return new DerivedObject(); } 19 public: 20 static const Type::Rtti& TypeId() 21 { 22 const static Type rtti[] = { Object::TypeId,nullptr }; 23 const static Type::Rtti inst(rtti, "DerivedObject", "DerivedObject"_hash, New); 24 return inst; 25 } 26 virtual Type getType()const override { return TypeId; } 27 };
2.使用
1 Type objType = Object::TypeId; 2 Object* obj = new Object(); 3 Type pobjType = obj->getType(); 4 std::cout << pobjType.getName() << std::endl; 5 delete obj; 6 obj = new DerivedObject(); 7 std::cout << obj->getType().getName() << std::endl; 8 std::cout << obj->getType().isKindOf(objType) << std::endl; 9 switch (obj->getType().getHash()) 10 { 11 case "Object"_hash: 12 std::cout << "Object" << std::endl; 13 break; 14 case "DerivedObject"_hash: 15 std::cout << "DerivedObject" << std::endl; 16 break; 17 default: 18 break; 19 } 20 delete obj;
3.結果
Object DerivedObject true DerivedObject
4.優缺點
該代碼實現的是單繼承的,且不能使用在模板類上。
可以通過宏定義的方式,簡化代碼書寫。
1 class DerivedObject : public Object 2 { 3 DECL_RTTI(DerivedObject, Object); 4 };