2016-12-03 12 views
3

B.Stroustrupの "The C++ Programming Language(第4版)"からRTTIを読んでいます。英語は私の母国語ではないので、dynamic_cast<T*>(p)を使ってダウンキャスティングメカニズムの説明から正しい結論に至ったのかどうかはわかりません。それはそれは簡単にオブジェクトの型に関する必要な情報を保持する 場所を見つけることができますので、私は多型であることを、ポインタの型を必要と書籍C++ - TC++ PL RTTI dynamic_castダウンキャストとバーチャルテーブルの混乱(実装と同様)

からのdynamic_castの 実装テキストを簡素化し引用しています。 典型的な実装では、オブジェクトのクラス(§3.2.3)の仮想関数テーブル の型情報へのポインタを置くことによって、型情報オブジェクト '' (§22.5)をオブジェクトに添付します。 例: The image explaining the downcast 破線の矢印は、 サブオブジェクトのポインタを指定した 完全オブジェクトの開始を検出できるオフセットを表します。 dynamic_castを効率的に実装できることは明らかです( )。含まれるのは、基本クラスを表すtype_info オブジェクトの比較です。高価なルックアップや文字列 の比較は必要ありません。

私の混乱がラインから来て「破線の矢印は、多型サブオブジェクトへのポインタのみ 与え発見される完全なオブジェクトの開始を可能にするオフセットを表します。」この線から

私の控除は、次のとおり

をサブオブジェクトへのポインタを表すさ VTBL(仮想関数テーブル)に格納された塩基(又はサブオブジェクト)へのポインタと破線が存在すること

  • これは、多形サブオブジェクトへのポインタのみを与えたという行の2番目の部分と矛盾します。しかし、それは混乱を招きます。どのようにしてサブオブジェクトへのポインタを渡すことができますか?ダウンキャストしながら、我々は<>括弧内の派生クラス名Tを通過しdynamic_cast<T*>(p)構文の()括弧内のベース・クラス・オブジェクトPへのポインタ。

私の最初の点が妥当であるか、または真と考えられる場合の完全なプロセスとして。 次に私の次の仮説が成立していると言えますか?

仮説は::ダウンキャストしながら、型情報オブジェクト(type_info)は、基本クラスのtype_idに対して逐次比較される仮想関数テーブル内に存在するポインター(VTBL)が指します。前に述べた比較でtype_idp(またはpが指すオブジェクト)が見つかった場合は、派生クラスのオブジェクトが作成されます。サブオブジェクトへのポインタは仮想テーブルに格納されているので、ドライバクラスのサブオブジェクト(dynamic_cast<T*>(p)への入力引数)であるp(これは入力引数)から取得した基本クラスオブジェクトをmemcpy仮想関数テーブルにあるポインタから見つかった)。

私はこれについてグーグルではありますが、考えられる説明が見つかりませんでした。私がofftopicの場合、適切なStackExchangeモジュールに私を案内してください。

P.S:サイドノートでは、トピックの3.2.3は本の中の仮想テーブルを説明しています。これは行で終わります。

この仮想呼び出しメカニズムは、 「通常の関数呼び出し」メカニズム(25%以内)とほぼ同じ効率で行うことができます。

ここには25%以内の意味があります。再び私はこれについて私の仮説を持っていますが、誰かが私に結論を述べる方が良いでしょう。

最後に、クロスキャストがdynamic_castによってどのように識別または実装されているかについての情報は深く感謝します。

答えて

1

すべてのオブジェクト(サブオブジェクト)がすべて存在するため、コピーは行われません。いくつかの基底クラスがありますが、そのうちのいくつかは仮想継承を持つかもしれません。

vtables内のポインタ(固定アドレスではなくオフセットとして格納される可能性があります)は、異なるサブオブジェクトがオブジェクト全体のどこから開始されるかをランタイムが見つけ出すのを助ける1つの方法です。または、サブオブジェクトへのポインタからフルオブジェクトの開始を見つけることができます。明らかに、最初の基本クラスのみをオブジェクトの先頭に配置することができ、他の基本クラスはstart + offsetのように配置する必要があります。

仮想呼び出しは、直接関数呼び出しとほぼ同じ効率があります。マシンコードレベルでは、関数呼び出しはcall address_of_functionとコード化されています。アドレスは命令内に格納されます。

仮想呼び出しはcall *(vtable + offset)として実装できます。 vtableアドレスがレジスタに格納されている場合、多くのCPUが単一の命令でこの間接参照を行うことをサポートしています。コストは、実際の関数アドレスをフェッチするための1つの余分なメモリアクセスです。関数が何か重要なことをする場合、この余分なメモリアクセスは大きな違いをもたらさないでしょう。