Symbianプログラミング総括-深編-RTTIの実現と原理説明

14422 ワード

この文章は楊芹
一、前言
RTTI(ランタイムタイプ情報)は、C#の「a is A」、JAVAの「a instanceof A」など、現代の高度なプログラミング言語で一般的にサポートされている特性の一つです.いずれもRTTIの範疇に属する.しかし、Symbian OS C++はこの特性をサポートしていないため、Win 32、JAVAからSymbianへの開発者またはコードの移植に大きな不便をもたらし、本稿ではこの問題を解決する.
 
二、RTTIとは
RTTIとは、「ランタイムタイプ識別(Run-Time Type Identification)」または「ランタイムタイプ情報(Run-Time Type Information)」のことであり、プログラムは、ベースクラスのポインタまたは参照を使用して、これらのポインタまたは参照が指すオブジェクトの実際の派生タイプを検査することができる.
適用の場合によってサポートするRTTIの範囲が異なります.最も単純なRTTIは次のとおりです.
  • クラス識別(class identification)--クラス名またはIDを含む.
  • 継承関係(inheritance relationship)--実行期間の「ダウンコンバートタイプ」(downward casting)、すなわち動的変換タイプ(dynamic casting)をサポートします.
  • 三、Symbian OSにおけるRTTI
    Symbianシステムとその実行するハードウェア環境の制限のため、Symbianシステムのプログラミングは完全に普通のC++プログラムのように勝手に設計することができなくて、Symbian OS C++はRTTIに対するサポートを提供しません.だから、標準C++のdynamic_cast<>、typeid()およびtype_infoはサポートされていません.
     
    四、MFCコードを移植してRTTIを実現する
    VC++コンパイラは4.0版からRTTIをサポートしているが、MFC 4.xは、コンパイラの能力を使用してRTTIのサポートを完了していません.MFCには独自の方法がある(1.0版から).ここではMFCでRTTIを実現するコードを借りてSymbian OS C++RTTIのサポートを完了する.
    MFCにおけるRTTIの実現原理については、侯捷の「深入浅出MFC」ではすでに詳細に述べられており、基本原理はいくつかの特殊なマクロを用いて手動でコンパイル中にオブジェクト継承関係チェーンテーブルを決定することであり、ここでは具体的な原理を説明しない.
    我々が移植したのはVC++9.0でMFCがRTTIを実現するコードであり,侯捷が『深入浅出MFC』で提供したシミュレーションコードを使用しない.侯捷のコードには「書き込み可能な静的データ」が非常に多く存在するため、Symbian DLLや2 nd版のアプリでは使用できない.しかしながら、VC++9.0のMFCコードには上記のような問題はないので、Symbianコードのいずれかで使用することができる.
    ここをクリックしてRTTI実装コアコードをダウンロードします
    圧縮パッケージには2つのファイルが含まれている:Rtti.h、Rtti.cpp.この2つのファイルをプロジェクトに追加した後、RTTIを実現するクラスの設計に着手します.
    1、クラスの宣言:
    Rtti.hヘッダファイルのCRttiBaseは、MFCのCObjectに相当するRTTIプロパティを持つベースクラスであり、CBaseから継承され、RTTIプロパティを実装するすべてのクラスが派生し、宣言に特殊なマクロが追加されます.
    
      
    1 class CMyClass : public CRttiBase 2 { 3 DECLARE_DYNAMIC(CMyClass) 4 ... 5 };
    注:マクロDECLARE_DYNAMICの最初のパラメータは、現在のクラスのクラス名:CMyClassです.
    2番目のクラスがCMyClassから継承されていることを宣言します.同じように、DECLARE_を追加します.DYNAMICマクロ:
    
      
    1 class CMyClass1 : public CMyClass 2 { 3 DECLARE_DYNAMIC(CMyClass1) 4 ... 5 };
    注意:RTTIを実装する子は親から継承され、親はCRttiBaseから継承される必要があります.
    2、クラスの実現
    CMyClassとCMyClass 1の実装ソースファイルには、次の2行のコードが追加されます.
    
      
    1 IMPLEMENT_DYNAMIC(CMyClass, CRttiBase); 2 IMPLEMENT_DYNAMIC(CMyClass1, CMyClass);
    マクロIMPLEMENT_DYNAMICの最初のパラメータは現在のサブタイプで、2番目のパラメータは直接親タイプです.たとえば、CMyClassの直接親はCRttiBase、CMyClass 1の直接親はCMyClassです.
    3、RTTI特性の使用
    以上の簡単な2つのステップで、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 }
    コードからCMyClass 1の親はCMyClassであり、CMyClassの親はRTTIベースクラスCRttiBaseであり、CMyClass 2のベースクラスもCRttiBaseであり、CMyClass 1とCMyClass 2は関係を継承していないことがわかる.
    したがって、コード23〜25行目、abcの値はtrue、true、falseの順である.
    CRttiBase::IsKindOfメソッドは、C#の「is」キーワード、JAVAの「instanceof」キーワードに類似しており、あるクラスのランタイム情報が渡され、マクロ「RUNTIME_CLASS」は、あるクラスのランタイム情報「CRuntimeClass」が取得される.
    4、運転時情報
    ランタイム情報構造体CRuntimeClassは、作成時にクラスの情報を保存し、クラス名、クラスサイズ、親情報など、プログラムの実行時に確認します.これらの情報はマクロIMPLEMENT_DYNAMIC内部では、プログラムのコンパイル時にすでに確定しています.
    
      
    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タイプ.
    5、クラスとオブジェクトのランタイム情報を取得する
    クラスのランタイム情報を取得マクロRUNTIME_を使用CLASS:
    
      
    CRuntimeClass* classType = RUNTIME_CLASS(CMyClass);
    注意:上記のコードはC#の「Type classType=typeof(CTestClass);メソッドはクラスのタイプ情報を取得します.
    オブジェクトのランタイム情報を取得するには、CRttiBase::GetRuntimeClass()メソッドを使用します.
    
      
    CMyClass1 * mc1 = new (ELeave) CMyClass1; CRuntimeClass * rc = mc1 -> GetRuntimeClass();
    注意:上記のコードはC#の「Type classType=theClass.GetType();」と理解できます.メソッドオブジェクトのタイプ情報を取得します.
    どちらのメソッドもCRuntimeClass*を返します.
    6、ランタイム情報により動的にオブジェクトを作成する
    CRuntimeClassには、ランタイム情報によってオブジェクトを動的に作成できる「CreateObject」という方法があることに気づくかもしれません.これは、比較的複雑な機能を実現するために必要であることが多い.次のようになります.
    異なる部品を生産できる工場があり、生産できる部品のタイプは多種多様である.
    RTTIが実装されない前に、工場メソッドに大きなcase文を書き、異なる部品タイプを判断して異なるクラスの構造関数を呼び出す可能性があります.
    RTTIが実装されると、部品タイプとCRuntimeClassの間のハッシュ表を保持し、工場メソッドでハッシュ表に部品タイプを入力し、CRuntimeClassを見つけてCRuntimeClass::CreateObject()メソッドを呼び出すだけでよい.
    動的にオブジェクトを作成するには、関数宣言の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のタイプ情報は、動的にオブジェクトを作成する機能を提供することができる.
     
    五、注意事項
    CRttiBaseはRTTI特性のサポートを実現した親であり,システム自体はRTTIのサポートを提供していない.したがって、RTTIを実装するクラスはCRttiBaseから直接または間接的に継承されなければなりません.これは通常、私たちの設計に大きな影響を与えます.たとえば、クラスがアクティブなオブジェクトの場合、CActiveから継承され、RTTIプロパティも実装されます.CActiveとCRttiBaseはCBaseから継承されているため、以下の宣言は間違いです.
    
      
    class CMyActiveObject: public CActive, public CRttiBase {...}
    ここでは2つの方法で解決します.
  • Wrapperモードを採用し、CActiveをカプセル化し、インタフェース
  • を導出する.
  • rttiを修正する.hは、CRttiBaseがCBaseから継承されないようにし、RTTIベースのクラスごとに手動でベースクラスCBaseまたはその他を指定し、C++多重継承のサポートを使用してクラスの設計を実現する.
  • 六、参考文献
  • 深入浅出MFC,侯捷
  • 実行時にオブジェクトタイプを決定する方法(RTTI)
  • Symbian OS C++高効率プログラミング
  • この文章は楊芹