關於type_info總結


c++沒有反射機制,我們可以經由過程c++的說話特點去實現同樣的功能。本文介紹應用type_info實現的一些發射特點。

1 type_info簡介:

class type_info {
public:
_CRTIMP virtual ~type_info();
_CRTIMP int operator==(const type_info& rhs) const;
_CRTIMP int operator!=(const type_info& rhs) const;
_CRTIMP int before(const type_info& rhs) const;
_CRTIMP const char* name() const;
_CRTIMP const char* raw_name() const;
private:
void *_m_data;
char _m_d_name[1];
type_info(const type_info& rhs);
type_info& operator=(const type_info& rhs);
};

(注: c++0 x01增長了hash_code辦法,獲取類名對應的hash值)

應用type_info須要重視3點:

(1)type_info的機關函數和賦值操縱符都為私有。是以不要試圖去定義或復制一個type_info對象。創建type_info對象的獨 一辦法是應用typeid操縱符。若是想應用type_info的引用,可以應用const type_info& info = typeid(foo)。

(2) type_info::name返回的是類似於"class CBase*"之類的名字, 並且c++標准只是告訴編譯器須要實現type_info::name函數,不合編譯器編譯運行后輸出不一樣。

(3) 對於父類指針類型變量,typeid(ptr).name不具有多態性, 仍返回此父類的指針類名,如"class CBase*"。若是直接傳入對象如typeid(*ptr).name則具有多態性,將返回"class CDevievd"類似的子類類名。  

2 巧用type_info

(1) 獲得類名的一種辦法是在類中實現class_name()辦法,如 

class CDataType 
{
public:
virtual char* class_name() { return "CDataType"; }
};

這種辦法的一個毛病就是強迫每一個類必須實現這個函數,不然后續的工作就無法完成。

 

下面是一個為數據注冊創建者,並按照數據類型獲取創建者的例子,看一下它是如何工作的。

// 數據
class CDataType
{
public:
virtual char* class_name() { return "CDataType"; }
};
class CDataTypeA : public CDataType
{
public:
virtual char* class_name() { return "CDataTypeA"; }
};
class CDataTypeB : public CDataType
{
public:
virtual char* class_name() { return "CDataTypeB"; }
}

// 數據創建者
class CreatorType {};
class CreatorForDataA : public CreatorType {};
class CreatorForDataB : public CreatorType {};

typedef std::string KeyType;
static std::map<std::string, CreatorType*> nameMap;

void RegistCreator(KeyType key, CreatorType* creator)
{
nameMap[key] = creator;
}

CreatorType* GetCreator( CDataType* data )
{
return nameMap[data->class_name()];
}

void main()
{
RegistCreator( "CDataTypeA"new CreatorForDataA );
RegistCreator( "CDataTypeB"new CreatorForDataB );

CDataTypeA* dataA = new CDataTypeA;

CreatorType* creator = GetCreator(dataA);
}

 

為每個數據強迫加一個class_name虛函數看起來是否有點冗余?

下面我們用type_info來實現雷同的功能。

// 數據
class CDataType {};
class CDataTypeA : public CDataType {};
class CDataTypeB : public CDataType {};

CreatorType* GetCreator( CDataType* data )
{
return nameMap[typeid(*data).name()];
}

void main()
{
RegistCreator( "CDataTypeA"new CreatorForDataA );
RegistCreator( "CDataTypeB"new CreatorForDataB );

CDataTypeA* dataA = new CDataTypeA;

CreatorType* creator = GetCreator(dataA);
}

斗勁一下,這個版本的代碼要簡單很多了,也有較好的擴大性,或許我們可以放松一下了。

可是沒過幾許天題目就來了,有的同事愁悶多量的字符串斗勁會影響速度,固然map是很高效的。愁悶確切是不須要的,殺手鐧還在你的手中——hash_code。

hash_code是把字符串映射到一個獨一整數,應用整數作為map鍵值效力要比string高很多。空話不說,上代碼。

typedef int KeyType;
static std::map<KeyType, CreatorType*> nameMap;

void RegistCreator(KeyType key, CreatorType* creator)
{
nameMap[key] = creator;
}

CreatorType* GetCreator( CDataType* data )
{
return nameMap[typeid(*data).hash_code()];
}

void main()
{
RegistCreator( typeid(CDataTypeA).hash_code(), new CreatorForDataA );
RegistCreator( typeid(CDataTypeB).hash_code(), new CreatorForDataB );

CDataTypeA* dataA = new CDataTypeA;

CreatorType* creator = GetCreator(dataA);
}


若是你的c++版本不敷,發明type_info底子沒有hash_code辦法,沒有關系,可以應用下面的辦法庖代。

size_t hash_code( const type_info& info )
{
// hash name() to size_t value by pseudorandomizing transform
const char *_Keyval = info.name();
size_t _Val = 2166136261U;
size_t _First = 0;
size_t _Last = _CSTD strlen(_Keyval);
size_t _Stride = 1 + _Last / 10;

for(; _First < _Last; _First += _Stride)
_Val = 16777619U * _Val ^ (size_t)_Keyval[_First];
return (_Val);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM