私はJavaからcppに移行していますが、いくつかのcpp機能がどのように機能するかを理解するのに少し問題があります。ポリモーフィズムまたはタイプセーフキャストを使用する場合、cppはオブジェクトの正確なタイプを知る必要があります。Javaでは、すべてのオブジェクトにその定義クラスへのリンクがあるため、この情報を取得できます。しかし、cppではそうではありません(私は思う)、sizeof()演算子はオブジェクトフィールドが占めるものしか返さないため、タイプ情報が格納されている場所ではないと推測しています。私はここで間違っていますか?そうでない場合、cppはどのようにポリモーフィズムなどを管理しますか?
4 に答える
C++ ポリモーフィズムは仮想関数に限定されます。仮想関数を実装するために必要なのは、一般にvtableとして知られる、クラスに共通の関数ポインターのテーブルだけです。vtable へのポインターが各オブジェクトに追加されますが、vtable 自体は同じクラスのすべてのオブジェクトに共通です。
vtable の使用は C++ 標準では義務付けられていませんが、実際にはほぼ普遍的であることに注意してください。
C++ は、仮想メソッドを持つ型に対してのみ動的型イントロスペクションを実行できます。Java とは異なり、C++ メソッドはデフォルトで非仮想です。
クラスに仮想メソッドを追加した(通常の)結果は、コンパイラがvtableへのポインタを含む追加の隠しスロットをクラス構造に発行することです。vtable には、仮想メソッドのメソッド ポインター用のスロットと、動的型情報への追加のポインターが含まれています。vtable は、次の方法で使用されます。
- インスタンスで仮想メソッドを呼び出すと、vtable に従い、適切な vtable メソッド スロットを介して呼び出されます。
- 仮想メソッドを使用してクラスのインスタンスを呼び出す
typeid
と、動的型情報への vtable ポインターが追跡され、インスタンスの実際の (動的) 型が決定されます。 - 仮想メソッドを使用してクラスのインスタンスを呼び出す
dynamic_cast
と、動的な型情報への vtable ポインターがたどられ、それを使用してインスタンス ポインターが調整されます。C++ では複数の継承が許可されているため、同じオブジェクトへの異なる型のポインターがメモリ内の異なる場所を指している可能性があるため、これが必要です。
vtable へのポインター スロットは、クラス (またはその基本クラス) に仮想メソッドsizeof
がある場合、オブジェクト メンバー フィールドの合計よりも大きくなることを意味します。
C++ では、RTTI を使用しないことをお勧めします。RTTI を使用しなくても、非常に大きなアプリケーションを作成できます。オブジェクトの型を把握し、適切な型にキャストする必要があります。Java では if ( obj instanceof ClassA ) {} を使用できますが、C++ ではそのようなコードを見たいと思うでしょう。
あなたはリフレクションについて尋ねていますが、いいえ、C++にはそれがなく、それは意図的なものではありません。Stroustrop は、何かが壊れている兆候として、オブジェクトが常に「あなたは何ですか」という種類のメッセージを互いに照会している他の言語を見ました。偶然にも、メタプログラミングによって得られるリフレクションの量には制限があります。
C++ のリフレクションの欠如をこっそり回避する方法があります。void* への動的キャストは、最も派生したオブジェクトへのポインターを提供します。だから今、あなたはそのポインタを理解する必要があります. 独自のタイプ管理システムがある場合は、これを行うことができます。これは単純ではありません。ほぼ必然的にどこかで言語のルールを破りますが、チェックポイント/再起動の目的で頻繁に使用されます。