Symbian開(kāi)發(fā)總結(jié)--RTTI的實(shí)現(xiàn)及原理說(shuō)明
本文和大家重點(diǎn)學(xué)習(xí)一下Symbian開(kāi)發(fā)總結(jié)--RTTI的實(shí)現(xiàn)及原理說(shuō)明。RTTI(運(yùn)行時(shí)類(lèi)型信息)是被現(xiàn)代高級(jí)編程語(yǔ)言所普遍支持的特性之一,然而SymbianOSC++并不支持這個(gè)特性,這導(dǎo)致由Win32、JAVA轉(zhuǎn)向Symbian的開(kāi)發(fā)人員或者代碼的移植都帶來(lái)很大的不便,本文將解決這個(gè)問(wèn)題。
Symbian開(kāi)發(fā)總結(jié)--RTTI的實(shí)現(xiàn)及原理說(shuō)明
一、前言
  RTTI(運(yùn)行時(shí)類(lèi)型信息)是被現(xiàn)代高級(jí)編程語(yǔ)言所普遍支持的特性之一,如C#中的“aisA”、JAVA中的“ainstanceofA”都屬于RTTI的范疇。然而SymbianOSC++并不支持這個(gè)特性,這導(dǎo)致由Win32、JAVA轉(zhuǎn)向Symbian的開(kāi)發(fā)人員或者代碼的移植都帶來(lái)很大的不便,本文將解決這個(gè)問(wèn)題。
  
二、什么是RTTI
Symbian開(kāi)發(fā)中RTTI指的是“運(yùn)行時(shí)類(lèi)型識(shí)別(Run-TimeTypeIdentification)”或者“運(yùn)行時(shí)類(lèi)型信息(Run-TimeTypeInformation)”,程序能夠使用基類(lèi)的指針或引用來(lái)檢查這些指針或引用所指的對(duì)象的實(shí)際派生類(lèi)型。
隨著應(yīng)用場(chǎng)合之不同﹐所需支持的RTTI范圍也不同。最單純的RTTI包括:
類(lèi)識(shí)別(classidentification)──包括類(lèi)名稱(chēng)或ID。
  繼承關(guān)系(inheritancerelationship)──支持執(zhí)行時(shí)期的“往下變換類(lèi)型”(downwardcasting),亦即動(dòng)態(tài)變換類(lèi)型(dynamiccasting)。
  
三、Symbian開(kāi)發(fā)中的RTTI
  由于Symbian系統(tǒng)以及它運(yùn)行的硬件環(huán)境的限制,造成Symbian系統(tǒng)編程不能完全像一般C++程序設(shè)計(jì)隨心所欲,SymbianOSC++并不提供對(duì)RTTI的支持。所以,標(biāo)準(zhǔn)C++中的dynamic_cast<>、typeid()及type_info都是不被支持的。
  
四、移植MFC代碼實(shí)現(xiàn)RTTI
Symbian開(kāi)發(fā)中VC++編譯器從4.0版才開(kāi)始支持RTTI,但MFC4.x并未使用編譯器的能力完成其對(duì)RTTI的支持。MFC有自己一套沿用已久的辦法(從1.0版就開(kāi)始了)。在此,我們借用MFC中實(shí)現(xiàn)RTTI的代碼,來(lái)完成對(duì)SymbianOSC++RTTI的支持。
關(guān)于MFC中RTTI的實(shí)現(xiàn)原理,侯捷的《深入淺出MFC》里已經(jīng)有詳細(xì)的闡述,基本原理是使用幾個(gè)特殊的宏手動(dòng)的在編譯期間確定一個(gè)對(duì)象繼承關(guān)系鏈表,在此不再說(shuō)明具體原理。
我們移植的是VC++9.0中MFC實(shí)現(xiàn)RTTI的代碼,不使用侯捷在《深入淺出MFC》中所提供的模擬代碼。因?yàn)楹罱莸拇a中存在非常多的“可寫(xiě)的靜態(tài)數(shù)據(jù)”,將不能在SymbianDLL或者2nd版的APP中使用。然而,VC++9.0中的MFC代碼沒(méi)有存在以上問(wèn)題,所以可以再任何Symbian代碼中使用。
壓縮包內(nèi)包含兩個(gè)文件:Rtti.h、Rtti.cpp。將這兩個(gè)文件加入工程后,著手設(shè)計(jì)實(shí)現(xiàn)RTTI的類(lèi):
1、類(lèi)的聲明:
  Rtti.h頭文件中的CRttiBase是擁有RTTI特性的基礎(chǔ)類(lèi),此類(lèi)相當(dāng)于MFC中的CObject,它繼承自CBase,所有要實(shí)現(xiàn)RTTI特性的類(lèi)都要從此類(lèi)派生,并且在聲明加入一個(gè)特殊的宏:
 
- class CMyClass : public CRttiBase
 - {
 - DECLARE_DYNAMIC(CMyClass)
 - ...
 - };
 
注意:宏DECLARE_DYNAMIC中的第一個(gè)參數(shù)為當(dāng)前類(lèi)的類(lèi)名:CMyClass。
  聲明第二個(gè)類(lèi)繼承自CMyClass,同樣的,要加上DECLARE_DYNAMIC宏:
 
- 1 class CMyClass1 : public CMyClass
 - 2 {
 - 3 DECLARE_DYNAMIC(CMyClass1)
 - 4 ...
 - 5 };
 
注意:實(shí)現(xiàn)RTTI的子類(lèi)繼承自父類(lèi),而父類(lèi)必須繼承自CRttiBase。
2、類(lèi)的實(shí)現(xiàn)
  在CMyClass和CMyClass1的實(shí)現(xiàn)源文件分別加入以下兩行代碼:
 
- 1 IMPLEMENT_DYNAMIC(CMyClass, CRttiBase);
 - 2 IMPLEMENT_DYNAMIC(CMyClass1, CMyClass);
 
宏IMPLEMENT_DYNAMIC中的第一個(gè)參數(shù)為當(dāng)前子類(lèi)型,第二個(gè)參數(shù)為直接父類(lèi)型,如:CMyClass的直接父類(lèi)為CRttiBase,CMyClass1的直接父類(lèi)為CMyClass。
3、使用RTTI特性
  通過(guò)以上簡(jiǎn)單兩個(gè)步驟,我們就能使用RTTI特性了,完整代碼:
 
- 1 class CMyClass : CRttiBase
 - 2 {
 - 3 DECLARE_DYNAMIC(CMyClass)
 - 4 };
 - 5
 - 6 class CMyClass1 : CMyClass
 - 7 {
 - 8 DECLARE_DYNAMIC(CMyClass1)
 - 9 };
 - 10
 - 11 class CMyClass2 : CRttiBase
 - 12 {
 - 13 DECLARE_DYNAMIC(CMyClass2)
 - 14 };
 - 15
 - 16 IMPLEMENT_DYNAMIC(CMyClass, CRttiBase);
 - 17 IMPLEMENT_DYNAMIC(CMyClass1, CMyClass);
 - 18 IMPLEMENT_DYNAMIC(CMyClass2, CRttiBase);
 - 19
 - 20 LOCAL_C void MainL()
 - 21 {
 - 22 CMyClass1* mc1 = new (ELeave) CMyClass1;
 - 23 TBool a = mc1->IsKindOf(RUNTIME_CLASS(CMyClass));
 - 24 TBool b = mc1->IsKindOf(RUNTIME_CLASS(CRttiBase));
 - 25 TBool c = mc1->IsKindOf(RUNTIME_CLASS(CMyClass2));
 - 26 }
 
從代碼中可以看出CMyClass1的父類(lèi)為CMyClass,CMyClass的父類(lèi)為RTTI基類(lèi)CRttiBase,而CMyClass2的基類(lèi)也為CRttiBase,CMyClass1和CMyClass2沒(méi)有繼承關(guān)系。
所以,代碼第23至25行,abc的值依次為true、true、false。
CRttiBase::IsKindOf方法類(lèi)似于C#中的“is”關(guān)鍵字、JAVA中的“instanceof”關(guān)鍵字,傳入的是某個(gè)類(lèi)的運(yùn)行時(shí)信息,而宏“RUNTIME_CLASS”獲取的是某個(gè)類(lèi)的運(yùn)行時(shí)信息“CRuntimeClass”。
4、運(yùn)行時(shí)信息
  “運(yùn)行時(shí)信息”結(jié)構(gòu)體CRuntimeClass在創(chuàng)建時(shí)將類(lèi)的信息保存以便程序運(yùn)行時(shí)查閱,其中包括類(lèi)名、類(lèi)大小、父類(lèi)信息等。這些信息在宏IMPLEMENT_DYNAMIC內(nèi)部,在程序編譯的時(shí)候就已經(jīng)確定:
 
- 1 struct CRuntimeClass
 - 2 {
 - 3 const char* iClassName;
 - 4 TInt iObjectSize;
 - 5 TUint iSchema;
 - 6 CRttiBase* (*iCreateObjectProc)();
 - 7 CRuntimeClass* iBaseClass;
 - 8 CRttiBase* CreateObject();
 - 9 TBool IsDerivedFrom(const CRuntimeClass* aBaseClass) const;
 - 10 CRuntimeClass* iNextClass;
 - 11 };
 
注:CRuntimeClass可以理解為C#中的System.Type類(lèi)型。
5、Symbian開(kāi)發(fā)中獲取類(lèi)和對(duì)象的運(yùn)行時(shí)信息
獲取類(lèi)的運(yùn)行時(shí)信息使用宏RUNTIME_CLASS,如:
CRuntimeClass* classType = RUNTIME_CLASS(CMyClass);
注:以上代碼可以理解為C#中的“TypeclassType=typeof(CTestClass);”方法取類(lèi)的類(lèi)型信息。
獲取對(duì)象的運(yùn)行時(shí)信息使用CRttiBase::GetRuntimeClass()方法,如:
  CMyClass1* mc1 = new (ELeave) CMyClass1;
  CRuntimeClass* rc = mc1->GetRuntimeClass();
注:以上代碼可以理解為C#中的“TypeclassType=theClass.GetType();”方法取對(duì)象的類(lèi)型信息。
兩種方法均返回CRuntimeClass*。
6、通過(guò)運(yùn)行時(shí)信息動(dòng)態(tài)創(chuàng)建對(duì)象
大家可能會(huì)注意到CRuntimeClass有一個(gè)方法叫“CreateObject”,此方法能夠通過(guò)運(yùn)行時(shí)信息動(dòng)態(tài)的創(chuàng)建對(duì)象。這在某些實(shí)現(xiàn)比較復(fù)雜的功能往往是很有必要的。如:
有一個(gè)工廠,能夠生產(chǎn)不同的零件,而能夠生產(chǎn)的零件的類(lèi)型是多種多樣的。
在沒(méi)有實(shí)現(xiàn)RTTI之前,我們可能會(huì)在工廠方法里寫(xiě)一個(gè)很大的case語(yǔ)句,針對(duì)不同的零件類(lèi)型進(jìn)行判斷從而調(diào)用不同類(lèi)的構(gòu)造函數(shù)。
而實(shí)現(xiàn)了RTTI后,我們只需要保持一個(gè)零件類(lèi)型和CRuntimeClass之間的哈希表,在工廠方法中向哈希表傳入零件類(lèi)型,找到CRuntimeClass后調(diào)用CRuntimeClass::CreateObject()方法即可。
  要實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象,必須把函數(shù)聲明中的DECLARE_DYNAMIC改為DECLARE_DYNCREATE,把IMPLEMENT_DYNAMIC改為IMPLEMENT_DYNCREATE即可。如:
 
- 1 class CMyClass : CRttiBase
 - 2 {
 - 3 DECLARE_DYNCREATE(CMyClass)
 - 4 };
 - 5
 - 6 IMPLEMENT_DYNCREATE(CMyClass, CRttiBase);
 
  這樣,CMyClass的類(lèi)型信息就能夠提供動(dòng)態(tài)創(chuàng)建對(duì)象的功能了。
  
五、注意事項(xiàng)
CRttiBase是實(shí)現(xiàn)了對(duì)RTTI特性支持的父類(lèi),系統(tǒng)本身沒(méi)有提供對(duì)RTTI的支持。所以,要實(shí)現(xiàn)RTTI的類(lèi)必須直接或間接的繼承自CRttiBase,這通常會(huì)對(duì)我們的設(shè)計(jì)造成很大的影響。如:如果一個(gè)類(lèi)為活動(dòng)對(duì)象,繼承自CActive,它又要實(shí)現(xiàn)RTTI特性,顯然以下聲明是錯(cuò)誤的,因?yàn)镃Active與CRttiBase都繼承自CBase:
class CMyActiveObject: public CActive, public CRttiBase {...}
在此有兩種方法解決:
采用Wrapper模式,封裝CActive并導(dǎo)出接口
  通過(guò)修改rtti.h,使CRttiBase不繼承自CBase,每個(gè)基于RTTI的類(lèi)都手動(dòng)的指定基類(lèi)CBase或其它,然后使用C++多重繼承的支持實(shí)現(xiàn)類(lèi)的設(shè)計(jì)。
  
六、參考文獻(xiàn)
深入淺出MFC,侯捷
如何在運(yùn)行時(shí)確定對(duì)象類(lèi)型(RTTI)
SymbianOSC++高效編程















 
 
 






 
 
 
 