vtableへのポインターは、階層内の各コンストラクターに入ると更新され、次に各デストラクタに入ると更新されます。vptrは基本クラスを指し始め、さまざまなレベルが初期化されると更新されます。
これは実装で定義されていることを多くの人から読んでいますが、これはvtableの選択全体であるためですが、実際には、すべてのコンパイラがvtableを使用し、vtableアプローチを選択すると、標準ではそのタイプがランタイムオブジェクトは、実行中のコンストラクタ/デストラクタのオブジェクトです。つまり、動的ディスパッチメカニズムが何であれ、構築/破壊チェーンをトラバースするときに調整する必要があります。
次のコードスニペットについて考えてみます。
#include <iostream>
struct base;
void callback( base const & b );
struct base {
base() { callback( *this ); }
~base() { callback( *this ); }
virtual void f() const { std::cout << "base" << std::endl; }
};
struct derived : base {
derived() { callback( *this ); }
~derived() { callback( *this ); }
virtual void f() const { std::cout << "derived" << std::endl; }
};
void callback( base const & b ) {
b.f();
}
int main() {
derived d;
}
標準では、そのプログラムの出力は、、、、であることが義務付けられていますがbase
、derived
関数derived
への4つの呼び出しすべてからbase
の呼び出しcallback
は同じです。実装できる唯一の方法は、構築/破棄の進行に合わせてオブジェクトのvptrを更新することです。