C++のRTTIメカニズム

5227 ワード

1 RTTIコンセプト
C++オブジェクトモデルからのRTTIの実現原理
RTTI(Run Time Type Identification)は、ランタイムタイプ識別によって、プログラムがベースクラスのポインタまたは参照を使用して、これらのポインタまたは参照が指すオブジェクトの実際の派生タイプを検査することができる.
1.1 RTTIメカニズムの生成
なぜRTTIというメカニズムが現れるのかは,C++言語そのものと関係がある.他の多くの言語と同様に、C++は静的タイプの言語です.そのデータ型はコンパイル期間中に決定され、実行時に変更できません.しかし、オブジェクト向けプログラミングにおけるマルチステート性の要件のため、C++のポインタまたはリファレンス(Reference)自体のタイプは、実際に表す(指向またはリファレンス)タイプと一致しない可能性があります.マルチステートポインタを実際にオブジェクトを指すタイプに変換する必要がある場合があります.実行時のタイプ情報を知る必要があります.これにより、実行時のタイプ識別の要件が発生します.Javaと比較して,C++がランタイムタイプ情報を得るにはRTTIメカニズムのみであり,C++が最終的に生成したコードはマシンに直接関係している.
2 typeidとdynamic_castオペレータ
C++は、以下の2つの操作によりRTTIを提供する.
(1)式またはタイプ名の実際のタイプを返すtypeid演算子.
(2)dynamic_cast演算子.ベースクラスのポインタまたは参照を派生クラスタイプのポインタまたは参照に安全に変換します.
2.1 typeid
C++の多態性(実行時)は虚関数で実現され,多態性のオブジェクトではプログラムコンパイル段階でオブジェクトのタイプを決定することはできない.クラスに虚関数が含まれている場合、そのベースクラスのポインタは派生クラスのオブジェクトを指すことができます.この場合、ベースクラスのポインタがどのオブジェクトを指しているのか分からない場合があります.タイプの決定は、実行時に実行時のタイプIDを使用して行います.オブジェクトのタイプを取得するために#includeのtypeid関数を使用することができるが、typeid関数の主な役割は、typeid(a)の使用など、現在の変数がどのようなタイプであるかをユーザに知らせることである.name()は変数aがどのようなタイプであるかを知ることができる.
2.2 dynamic_キャスト強制変換演算子
ベースクラスタイプのポインタまたは参照を派生クラスタイプのポインタまたは参照に変換することをダウンシフト(downcast)と呼ぶ.dynamic_cast演算子の役割は、安全で効率的にダウンシフトすることです.
この変換子は、派生クラスを指すベースクラスポインタまたは参照を派生クラスのポインタまたは参照に変換するために使用されます.dynamic_に注意してください.cast変換子は、dynamic_という式の虚関数を含むクラスにのみ使用できます.Cast(式)は、式を変換するターゲットタイプ、例えば虚関数を含むベースクラスBとベースクラスBから派生した派生クラスDの場合、B*pbを指す.D *pd, md; pb=&md; pd=dynamic(pb); 最後の文は、派生クラスDを指すベースクラスポインタpbを派生クラスDに変換するポインタを表し、このポインタを派生クラスDのポインタpdに付与することは、ポインタpdが派生クラスを指すのになぜpd=&mdではないのか、意味がないと感じる人もいるかもしれません.このようにするのはもっと直接的ですか?
派生クラスDに固有のメンバー関数g()を含む派生クラスDに固有のメンバー関数g()を含む派生クラスDに固有のメンバーにアクセスするために、派生クラスのベースクラスポインタBを指す場合など、強制的に変換する必要があるため、派生クラスDに固有のメンバーにアクセスする目的を達成するために、派生クラスDに固有のメンバー関数g()を含むこの場合、このメンバーdynamic_にアクセスできます.cast(pb)->g();なぜならdynamic_cast変換の結果は派生クラスへのポインタであるため、派生クラス固有のメンバーにアクセスできます.しかし、この文は元のポインタのタイプに影響しない.すなわち、ベースクラスポインタpbはベースクラスBを指している.
dynamic_cast変換子はポインタまたは参照にのみ使用できます.dynamic_cast変換子は、虚関数を含むクラスにのみ使用できます.dynamic_cast変換オペレータは、タイプ変換を実行するときにまず変換に成功するかどうかを確認し、変換に成功すれば変換し、変換に失敗した場合はポインタで0値を戻し、変換が参照であればbad_を放出します.cast異常なのでdynamic_を使用していますcast変換間でif文を使用して、pd=dynamic_などの変換に成功したかどうかをテストします.cast(pb); if(pd){...}else{...}またはif(dynamic_cast(pb){...}else{...}をテストします.
3 static_castとdynamic_castオペレータの比較
C++からstatic_castとdynamic_キャスト強制タイプ変換
3.1 static_cast(コンパイル時タイプチェック)
使用法:static_cast(expression)は、expressionをtype-idタイプに変換する演算子ですが、実行時タイプチェックで変換の安全性を保証するものではありません.主に以下のような使い方があります.(1)intをcharに変換し、intをenumに変換するなど、基本データタイプ間の変換に使用します.しかし、このような変換の安全性は、intをcharに変換する場合、charがintの値を格納するのに十分なビットビットビットがない場合(int>127またはint(2)空ポインタをターゲットタイプに変換する空ポインタ(3)任意のタイプの式タイプをvoidタイプに変換(4)クラス階層における親クラスと子クラス間のポインタと参照の変換に使用する.以上の(4)点目について、上り変換(子から親へ)と下り変換(親から子へ)の2つの形式の変換が存在する.static_の場合cast、上り変換では安全ですが、下り変換では安全ではありません.なぜですか.だってstatic_castの変換は乱暴で、タイプ変換文に指定された情報(カッコ内のタイプ)のみに基づいて変換されます.この変換は、親のすべてのデータ・メンバーと関数メンバーを常に含むため、子から親に変換するポインタ・オブジェクトは、親のメンバーに何の心配もなくアクセスできます.下り変換がなぜ安全ではないのかはstatic_castはコンパイル時にタイプを堅持するだけで、実行時のタイプチェックはなく、具体的な原理はdynamic_castで説明します.
3.2 dynamic_キャスト(運転時タイプチェック)
dynamic_castは主にクラス階層内の親クラスと子クラス間のポインタと参照の変換に使用されます.実行時タイプチェックがあるため、下り変換のセキュリティを保証できます.セキュリティとは何ですか.すなわち、変換に成功すると変換後の正しいタイプのポインタが返され、変換に失敗するとNULLが返されます.static_castは、変換に失敗してもNULLを返さないため、下り変換時に安全ではありません.アップリンク変換の場合dynamic_キャストとstatic_castは同じです.下り変換について、下り変換といえば、C++では、parent*P 1=new Children()のような親ポインタでサブクラスオブジェクトを指すことが一般的であることを理解する必要があります.しかし、このポインタは親定義のデータメンバーと関数にしかアクセスできません.これはC++の静的結合ですが、Children*P 1=new parentなどの親オブジェクトを指すサブクラスタイプポインタは一般的に定義されません.この定義方法は生活習慣に合わず、プログラム設計も面倒です.これで説明もしましたが、上り変換ではstatic_castとdynamic_cast効果は同じで、アップコンバートされたオブジェクトは一般的にサブクラスオブジェクトを指すサブクラスタイプポインタであるため、安全です.一方、下り変換では、サブクラスオブジェクトへの親タイプポインタを定義できるため、static_castはコンパイル時にのみタイプチェックを行いdynamic_castが実行時タイプチェックである場合は、状況に応じて異なります.以下、コードにより説明する
class Base { virtual void fun(){} };

class Derived : public Base { };

(1)ダウンコンバートが必要なため、親タイプのポインタBase*Pを定義する必要がありますが、子が親を継承するため、親ポインタは親オブジェクトを指すことも、子オブジェクトを指すこともできます.これがポイントです.Pがサブクラスオブジェクトを指している場合はdynamic_キャストとstatic_キャストは次のように変換できます.
Base *P = new Derived();
Derived *pd1 = static_cast(P);
Derived *pd2 = dynamic_cast(P);

(2)ただし,Pが子オブジェクトではなく親オブジェクトを指す場合は,以下のようになる.
Base *P = new Base;
Derived *pd3 = static_cast(P);
Derived *pd4 = dynamic_cast(P);

以上の変換でstatic_cast変換はコンパイル時にエラーが報告されず、サブクラスオブジェクトポインタ(仮想)を返すこともできますが、これは安全ではありません.実行時に問題がある可能性があります.サブクラスには親にないデータと関数メンバーが含まれているので、変換の文字通りの考えを理解する必要があります.変換は何ですか.変換とは、オブジェクトをあるタイプから別のタイプに変換することであり、このときpd 3でサブクラスにあるが親クラスにないメンバーにアクセスすると、アクセスの限界を越えるエラーが発生し、プログラムがクラッシュします.そしてdynamic_castは、実行時タイプチェック機能を有するため、Pのタイプをチェックすることができ、上記の変換が不合理であるため、NULLを返す.
(3)まとめ:
C++の階層タイプ変換は、上り変換と下り変換の2つにほかならない.アップリンク変換の場合static_castとdynamic_castの効果は同じで、すべて安全ですが、基本的に上り変換は必要ありません.≪ダウンリンク変換|Down Transformation|emdw≫:変換するデータがターゲット・タイプのデータであることを確認する必要があります.つまり、変換する親タイプ・ポインタが本当にサブクラス・オブジェクトを指しているかどうかに注意する必要があります.もしそうであればstatic_castとdynamic_castはすべて成功することができます;staticでなければcastは返すことができますが、安全ではありません.アクセス限界エラーが発生する可能性があります.dynamic_castは、実行時タイプチェック中に、このプロシージャが変換できないと判定し、NULLを返す.