転載:https : //blog.csdn.net/qq_36359022/article/details/818702
C ++仮想関数テーブルは、C ++ポリモーフィズムをサポートするための重要なテクノロジーであり、C ++動的バインディングテクノロジーの中核です。
1.メモリ分散
基本クラスClassA、基本クラスを継承する派生クラスClassBがあり、基本クラスに仮想関数があり、派生クラスが基本クラスの仮想関数を実装するとします。
:我々は、一般的に二つの方法で、多型の性質に手をコードを使用する
(1)にClassAのClassBの新しい新しい= A *();
(2)ClassBのB; A =&B * A級の、
二つの方法の上に使用されています基本クラスポインターは派生クラスインスタンスを指しますが、最初のインスタンスは新しいキーワードを使用してヒープに割り当てられ、2番目のインスタンスはスタックに割り当てられるという違いがあります。
上の図を参照してください。2つの異なる作成方法は、派生クラスオブジェクトインスタンスの場所にのみ影響します。
左の図を例にとると、ClassA * aはスタック上のポインタです。このポインターは、ヒープにインスタンス化されたサブクラスオブジェクトを指します。基本クラス、サブクラスオブジェクトの仮想関数がメンバー関数とメンバー変数に加えてある場合、コンパイラーはクラスの仮想関数テーブルへのポインター(ここではクラスClassB)を自動的に生成します仮想関数テーブルへのポインター。親クラスポインターは、仮想関数テーブルポインターを通じて、仮想関数テーブル内のすべての仮想関数を呼び出すことができます。
次に、クラスの仮想関数テーブルとクラスインスタンスの仮想テーブルポインター
まず、継承については考慮しません。クラスに仮想関数がある場合、クラスにはそのクラスに属する仮想関数テーブルがあります。このクラスのすべてのインスタンス化されたオブジェクトには、クラスの仮想関数テーブルを指す仮想関数テーブルポインターがあります。
また、最初の部分の図から、クラスのインスタンスがヒープ上またはスタック上にあることがわかります。つまり、クラスには多くのインスタンスが存在する可能性があります。ただし、クラスには仮想関数テーブルが1つしかありません。コンパイル時に、クラスの仮想関数テーブルが決定されるため、読み取り専用データセクションに配置されます。
呼び出しプロセスは次のとおりです。
たとえば、次のとおりです。
A * p =新しいB()
p-> func()
実際の呼び出しプロセスは次のとおりです。
vt = p-> vptr; //仮想テーブルを取得
vf = vt [0]; //関数のアドレスを取得します。これは、仮想関数が1つしかないため、仮想テーブルのfunのラベルは0です
p-> vf()
3、通常継承・多重継承の仮想関数テーブル
継承の場合、基本クラスに仮想関数がある限り、サブクラスは実装されているかどうかに関係なく仮想関数テーブルを持っています。
基本クラスの仮想関数と同じ名前のサブクラスの関数も自動的に仮想に追加されます。
まず、サブクラスは基本クラスの仮想関数テーブルを継承し、基本クラスの仮想関数が書き換えられると、仮想関数テーブルが更新されます。基本クラスの仮想関数が書き換えられない場合、サブクラスと基本クラスの仮想関数テーブルの内容は同じです。
ただし、基本クラスの仮想関数テーブルとサブクラスの仮想関数テーブルは同じテーブルではありません。
4、多重継承の仮想関数テーブル(同時に複数の基本クラスを継承)
多重継承とは、複数の基本クラスを同時に継承するクラスを指します。これらの基本クラスに仮想関数があると仮定します。つまり、各基本クラスに仮想関数テーブルがあるとすると、サブクラスと仮想関数テーブルの論理的な結果はどうなりますか?え?
多重継承の場合、基本クラスが基本クラスとしてカウントする仮想関数を持っている限り、基本クラスと同じ数の仮想関数テーブルポインターがあります。
注:
1.サブクラス仮想関数は、各親クラスの同じ名前のすべての仮想関数をカバーします。
2.親クラスには仮想関数がなく、子クラスにはそれがある最初の仮想関数テーブルに書き込まれ、親クラスポインターで呼び出すことはできません。
3.親クラスには仮想関数があり、サブクラスにはない場合、それらは上書きされません。呼び出すことができるのは、サブクラスと親ポインターのみです。