翻看C++的書,對RTTI的講解都很困惑,"你知道你的對象是哪個類嗎?","RTTI常用於調試和數據庫程序"對這些講解本來就對"運行時類型識別"這個詞很迷惑的我來說就更迷糊了.我認爲還是C++ PRIMER這本書講的很好.一開始就給出了答案:RTTI允許"用指向基類或引用來操縱對象"的程序能夠獲取到"這些指針所指對象"的實際派生類型.這句話雖然很苦澀難懂,但講的再清楚不過了.RTTI就是對多態的類型轉換的反操作,我講的可能不是很標準.沒有人家的講的話那麼嚴謹,呵呵.對RTTI基本使用dynamic_cast 和 typeid兩種操作方式.
第一:dynamic_cast操作.無論怎麼看書我對這個操作都很迷茫,越看越覺得有點懂還有點不懂.後來我仔細的思考後感覺dynamic_cast使用必須滿足一個條件,就是所操縱的對象必須有一個虛函數.我知道C++中的對象實際上就是指向內存中的一些變量,而虛函數就是變量多一個函數指針.這樣就得到答案:dynamic_cast實際上就是判斷兩個對象的虛函數指針是不是指向同一個函數地址.那麼dynamic_cast就是一種強制類型轉換操作,它提供一種安全的工作方式,可以將父類轉換成子類.
dynamic_cast有指針判斷和引用判斷兩種,下面用C++ PRIMER上的例子進行舉例:
class employee{ public: virtual int salary(); }; class programmer:public employee{ public: int salary(); int bonus(); }; //使用指針 void company::payroll(employee *pe){ if (programmer *pm=dynamic_cast<programmer*>(pe)) { pm->bonus(); } } //使用引用 void company::payroll(employee &re){ try { programmer &rm=dynamic_cast<programmer &>(re); rm.bonus(); } catch (std::bad_cast) { } }
第二:typeid操作.對typeid的理解好象容易的多,它返回type_info這個類,根據書上的講解,type_info這個類是編譯器實現的,這個類根據不同的編譯器會有不同的支持,包括比較兩個對象,對象的類名,還會有函數清單,類型對象的內存佈局等.那比較兩個對象就可以用這個類實現更強大的功能.對於type_info這個類的使用我有很多疑問,它是跟類一起創建的?還是跟對象一起創建的?如果保存對象是不是也要保存thpe_info這個類對象呢?可是這些書上都沒有答案。畢竟這是一本初級的書,可能需要到高級或實際編程中獲得答案。type_info的構造函數是私有的,這個類必須由typeid才創建,那就說明typeid是type_info類的一個友元.但讓我非常迷惑的是typeid寫法.還是以C++ PRIMER上的例子的來說明.
#include <typeinfo> employee *pe =new manager; employee re=*pe; //這裏爲什麼不能用在RTTI呢? if(typeid(pe)==typeid(employee*))//true if(typeid(pe)==typeid(manager*))//false if(typeid(pe)==typeid(employee))//false if(typeid(pe)==typeid(manager))//false //這個還好理解吧 if(typeid(*pe)==typeid(manager))//true if(typeid(*pe)==typeid(employee))//false //這個也可以 if(typeid(re)==typeid(manager))//true if(typeid(re)==typeid(employee))//false //這裏又不行了. if(typeid(&re)==typeid(employee*))//true if (typeid(&re)==typeid(manager*))//false
我對這樣的寫法很難理解,到底哪個寫法是正確的呢?經過我仔細的閱讀才明白原來typeid不但可以用在RTTI上.還可以用在識別各種類,變量和常量上.用於識別它們的數據類型.比如C++ PRIMER上的例子:
int i; cout<<typeid(i).name()<<endl;//打印:int cout<<typeid(8.16).name()<<endl;//打印:double class Bass{/*沒有虛函數*/}; class Derived :public Bass{/*沒有虛函數*/}; Derived dobj; Bass *pb=&dobj; cout<<typeid(*pb).name()<<endl;//打印:Base
那麼怎麼寫纔可以用在RTTI的類型轉換上呢?那就是表達式是一個類的類型.而不是一個類的指針.
上面對RTTI的學習筆記都寫完了,也可能有理解錯誤的地方,在這裏記錄一下.方便今後使用的時候來閱讀.