ええと、それは興味深い質問ですが、非常に系統的な方法でそれに答えようとしましょう!!!
コンパイラが次のような呼び出しを解決する必要があるとしましょう: *
a->someFunc();
*。
これで、コンパイラは次の手順を体系的に進めます。
1.) まず、コンパイラは変数 a の宣言された型を認識しているため、オブジェクト a ( ) の宣言された型にlets call this, class A for time being
someFunc() という名前のメソッドがあり、それが public でなければならないかどうかをチェックします。このメソッドは で宣言するか class A
、クラス A の基本クラスの 1 つから派生したメソッドにすることができますが、コンパイラには関係なく、アクセス指定子が であることでその存在をチェックするだけpublic
です。
- 言うまでもなく、このステップでエラーが発生すると、コンパイラ エラーが発生します。
2.) 次に、メソッドがクラス A の一部であることが検証されると、コンパイラは正しいメソッドへの呼び出しを解決する必要があります。これは、多くのメソッドが同じ名前で存在する可能性があるためです (関数のオーバーロードのおかげです)。この正しい方法を解決するプロセスを と呼びoverloading resolution
ます。コンパイラは、呼び出されたメソッドのシグネチャを、クラスの一部であるオーバーロードされたすべてのメソッドと照合することでこれを実現します。そのため、すべてのsomeFunc() s
正しい someFunc() (呼び出されたメソッドと署名を照合する) のみが検出され、さらに検討されます。
3.) ここで難しい部分があります。クラス A ( ) のサブクラスの 1 つで someFunc() がオーバーライドされている可能性がありlets call this class AA and needless to say it is some subclass of A
、その変数 a (型 A であると宣言されている) が実際に参照している可能性があります。クラス AA のオブジェクト (これは C++ でポリモーフィズムを有効にするために許可されています)。ここで、基本クラス (つまり、クラス A) で someFunc() メソッドが type であると宣言されvirtual
、 someFunc() が A のサブクラス (AA または A と AA の間のクラス) によってオーバーライドされている場合、 someFunc() の正しいバージョンは、コンパイラによって検出される必要があります。
ここで、あなたがコンパイラであり、クラスAA
にこのメソッドがあるかどうかを調べるタスクを持っていると想像してください。明らかに、クラス AA はこのメソッドを持ちます。なぜなら、それは A のサブクラスであり、クラス A での A のパブリック アクセスはコンパイラによってステップ 1 で既に検証されているからです !!! . しかし、代わりに、前の段落で述べたように、 someFunc() はクラス AA (または A と AA の間の他のクラス) によってオーバーライドされる可能性があり、これはコンパイラがキャッチする必要があるものです。したがって、(コンパイラをプレイしているため) クラス A から始まり、クラス AA で終わる最下位 (継承ツリーの最下位) のオーバーライドされたメソッド someFunc() を見つけるために体系的なチェックを行うことができます。この検索では、オーバーロードの解決で検証されたものと同じメソッド シグネチャを探します。このメソッドは、呼び出されるメソッドになります。
この検索は毎回行われているのでしょうか。...まあ、そうではありません。コンパイラは、これを毎回見つけるオーバーヘッドを認識しているVirtual Table
ため、すべてのクラス タイプに対して呼び出されるデータ構造を維持します。仮想テーブルは、メソッド シグネチャ (パブリックにアクセス可能) から関数ポインターへのマッピングと考えてください。この仮想テーブルは、コンパイル プロセス中にコンパイラによって作成され、プログラムの実行中にメモリ内に保持されます。この例では、クラス A とクラス AA の両方に独自の仮想テーブルがあります。また、コンパイラーがクラス AA で someFunc() を見つける必要がある場合 (変数 a が指す実際のオブジェクトはタイプ AA であるため)、クラス AA の仮想テーブルを介して関数ポインターを見つけるだけです。これは、テーブルへのハッシュが単純であり、一定時間の操作です。
よろしく
AVID