仮想関数テーブル

仮想関数テーブル（かそうかんすうテーブル、）あるいはvtableは、プログラミング言語の実装において動的なポリモーフィズム、すなわち実行時のメソッドの束縛を実現するために用いられる機構である。
あるプログラムが、継承関係にある複数のクラス（データ型）を持っているとする。たとえばスーパークラス codice_1 と二つのサブクラス codice_2 と codice_3 において、クラス codice_1 が codice_5 という仮想関数（仮想メソッド）を定義しており、サブクラスは適切な実装（鳴く、吠えるといった）を行うものとする。
プログラムがcodice_5メソッドをcodice_1へのポインタcodice_8（codice_1 クラスおよび codice_1 の任意のサブクラスを指すことができる）に対して呼び出すと、実行環境は、codice_8が指す実際のオブジェクトの種類（型）に応じてどの実装を呼び出すかを決定しなければならない。
このような動的な割り当てを実現するには様々な方法があるが、C++および関連するプログラミング言語（D言語、Java、C#など）では、vtableによる方法が一般的である。
オブジェクトのインターフェイスを実装から分離する言語（Visual Basic や Delphi など）でも、異なるメソッドポインタの集合を用いるだけで、異なる実装をオブジェクトが使用できるため、vtable による方法を採用する傾向にある。
C言語はオブジェクト指向プログラミングの機能を言語仕様としてサポートしないが、関数ポインタを利用することで仮想関数を模倣することができる。
vtable の実装.
C++ の標準では、動的なディスパッチがどのように実装されるべきかについて規定していないが、一般的にコンパイラは若干の変更を加えて共通の基本的なモデルを用いる。
典型的には、コンパイラは個々のクラスごとに別の vtable を作成する。オブジェクトが生成される際、vtable へのポインタ（仮想テーブルポインタ, vpointer, vptr）がオブジェクトの不可視のメンバー（フィールド）として追加される（通常は最初のメンバーとなる）。コンパイラはコンストラクタ内に"隠れた"コードを生成し、クラスのオブジェクトの vpointer が、対応する vtable のアドレスで初期化されるようにする。
例.
下記のクラスの宣言は C++ の文法に従うものとする：
class B1
public:
 int int_in_b1;
class B2
public:
 int int_in_b2;
これらは下記のクラスを派生させる。
class D : public B1, public B2
public:
 virtual void f2() {} // B2::f2() をオーバーライド
 int int_in_d;
B2 *b2 = new B2();
D *d = new D();
GNUコンパイラコレクション の g++ 3.4.6 は、オブジェクト codice_12 に対して下記の 32bit メモリレイアウトを生成する。
オブジェクト codice_13 のメモリレイアウト:
仮想でない関数（codice_14）は通常 vtable に現れないが、いくつかの例外もある（デフォルトコンストラクタなど）。
クラス codice_15 でメソッド codice_16 をオーバーライドしているが、これは codice_17の仮想関数テーブルを複製し、codice_18 へのポインタを codice_19 へのポインタで置き換えることで実現されている。
多重継承とthunk.
g++ コンパイラはクラス codice_15 の codice_21 と codice_17 からの多重継承を、基底クラスごとに一つずつの、二つの仮想関数テーブルを用いて実現する（多重継承を実現するには他にも方法があるがこれが最も一般的である）。これにより、キャストの際 "" () が必要になる。
下記のような C++ コードを考える:
D *d = new D();
B1 *b1 = dynamic_cast<B1*>(d);
B2 *b2 = dynamic_cast<B2*>(d);
codice_13 と codice_24 が実行時に同じメモリ位置を参照するが、
codice_12 は codice_26（codice_13 のメモリ配置の8バイト後方）を示す。
そのため、codice_12 は codice_13 内の codice_17 らしく見える領域、
すなわち codice_17 のインスタンスと同じメモリレイアウトを持つ部分を示す。
呼び出し.
呼び出しの際には、codice_32 の呼び出しの際は、codice_13 の codice_34 vpointer をたどり、vtable から codice_35 のエントリーを調べ、ポインタを取り出してコードを呼び出す。
単一継承（あるいは、単一継承のみ可能な言語）の場合、vpointer が常に codice_13 の最初の要素にあれば（多数のコンパイラでそうなっている）、下記のような擬似 C++ のコードに簡略化できる。
より一般的なケースでは、上記のようなcodice_13の codice_38、codice_19、codice_18 呼び出しはより複雑なものとなる。
これに対して、codice_41 の呼び出しはもっと単純である：
効率.
単なるコンパイルされたポインタへのジャンプである非仮想関数の呼び出しに対して、仮想関数の呼び出しは最低一度以上、余分にポインタをたどる操作や"fixup" が必要である。そのため、仮想関数の呼び出しは原理的に非仮想の関数呼び出しに対して低速である。実験によれば 6-13% の実行時間が単なる関数のディスパッチに用いられ、オーバーヘッドは場合によって 50% に達する。
さらに、 JIT コンパイルが使用できない環境では、仮想関数は通常インライン展開できない。テーブルの参照を行う部分を、たとえばインライン化された本体部分を条件文で実行させることも可能ではあるが、そうした最適化は一般的ではない。
オーバーヘッドを避けるため、コンパイラはコンパイル時に呼び出しが解決できる場合には vtable の生成を行わない。
従って、上記の codice_35 の呼び出しは、 codice_13 が現時点で codice_15 のみ保持しており、codice_15 が codice_35 をオーバーライドしないことをコンパイラが判断できるため、vtable の検索は必要なくなる可能性がある。コンパイラ（あるいは最適化プログラム）はプログラム内に codice_35 をオーバーライドする codice_21 のサブクラスがないことを検出することができるかもしれない。実装が明示的に指定されているため（this ポインタの fixup が必要ではあるが）codice_49 または codice_50 はおそらく vtable の検索を必要とすることはない。
比較、およびその他の方法.
vtable は一般的に動的なディスパッチを実現するための、性能上のよいトレードオフであるが、たとえば二分木ディスパッチといった代替の方法も存在する。
しかし、vtable は特殊な "this" パラメータでは のみ考慮しており、ディスパッチの際全てのパラメータの型が考慮される多重ディスパッチ（CLOS や Dylan）とは異なる。
vtables はまた、コンパイル時に単一の配列にメソッドを配置するため、ディスパッチが既知のメソッドのセットに限定されている場合のみうまく動作する。これはダック・タイピング言語（Smalltalk、Python、JavaScript、あるいは C++ のコンパイル時のテンプレート機構）とは対照的である。
上記の一つまたは両方をサポートする言語は、ディスパッチをハッシュテーブルの文字列検索や同等の手段で行うことが多い。ディスパッチを高速化する様々な方法があり（たとえば、メソッドの名前を intern 化やトークン化する、検索のキャッシュ、JITコンパイルなど）、ディスパッチの時間は全体的な処理時間にそれほどの影響を与えない。それでもなお、vtable の検索の方が明らかに高速である。また vtable は実装やデバッグが簡単で、文字列のハッシュテーブルよりも"Cの精神"に近い。