3
class A {
       public :
       void printSometext() {
       std::cout << "printing A" << std::endl;
       }
    };
class B {
       public : 
       void printSometext() {
       std::cout << "printing B" << std::endl;
       }
    };

int main() {
   A* a = new A();
   a->printSometext();
   return 0;
}

C++ オブジェクトがメンバー関数に関する情報を保持する方法。上記のコードを考えてみましょう。オブジェクト「a」でprintSometextを呼び出すと、呼び出す関数と正しいメソッドを見つける方法がわかります。オブジェクトのサイズを出力する場合、そのメンバー変数の合計サイズ (+alignments) を出力します。そのため、メンバー関数呼び出しがどのように行われるかについての内部情報を提供してください。

ありがとう、ダイマス

4

4 に答える 4

7

C++プログラミングの基本が間違っています。a実行時にはわかりませんprintSomeText。これらのタスクを実行するのは、上記のコードをバイナリコードに変換するコンパイラとリンカです。実行時には、一連の命令があります。

于 2011-03-21T07:25:26.497 に答える
4

ええと、それは興味深い質問ですが、非常に系統的な方法でそれに答えようとしましょう!!!

コンパイラが次のような呼び出しを解決する必要があるとしましょう: *

a->someFunc();

*。

これで、コンパイラは次の手順を体系的に進めます。

1.) まず、コンパイラは変数 a の宣言された型を認識しているため、オブジェクト a ( ) の宣言された型にlets call this, class A for time beingsomeFunc() という名前のメソッドがあり、それが 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

于 2011-03-21T08:00:20.423 に答える
3

アシャの答えに追加する(+1):

内部での動作を本当に理解したい場合は、アセンブリを学び、生成されたマシンコードを調べることをお勧めします。それが私がしたことです。

于 2011-03-21T07:28:25.600 に答える