いいえ、そのような可能性はありません。はvptr
、コンストラクターおよびデストラクタからのみ更新されます。
デストラクタからの更新は、非常に具体的な理由で行われます。クラスのデストラクタ内から呼び出されるすべての仮想関数が、階層内でA
定義されているA
かそれより上位の階層で定義されている仮想関数を呼び出すが、下位階層にあるクラスからの関数は呼び出さないことを確認するためです。vptr
基本的に、これは各コンストラクターでもポインターが更新されるのと同じ (対称的な) 理由です。
たとえば、この階層では
struct A {
virtual void foo() { std::cout << "A" << std::endl; }
~A() { foo(); }
};
struct B : A {
virtual void foo() { std::cout << "B" << std::endl; }
~B() { foo(); }
};
struct C : B {
virtual void foo() { std::cout << "C" << std::endl; }
~C() { foo(); }
};
C c;
オブジェクトのデストラクタ チェーン内の各デストラクタは、c
仮想関数の呼び出しを実行しますfoo
。C
will callのデストラクタC::foo
、B
will call B::foo
(not C::foo
) のデストラクタ、およびA
will call A::foo
(再び、 not C::foo
) のデストラクタ。これは、各デストラクタvptr
が独自のクラスの仮想テーブルへのポインタを明示的に設定するためです。
同じ動作のより複雑な例は、次のようになります。
struct A;
extern void (A::*fun)();
struct A {
virtual void foo() { std::cout << "A" << std::endl; }
~A() { (this->*fun)(); }
};
void (A::*fun)() = &A::foo;
struct B : A {
virtual void foo() { std::cout << "B" << std::endl; }
~B() { (this->*fun)(); }
};
struct C : B {
virtual void foo() { std::cout << "C" << std::endl; }
~C() { (this->*fun)(); }
};
C c;
違いは、この例ではvptr
および仮想メソッド テーブルを物理的に使用して呼び出しを解決する可能性が高いことです。前の例は通常、適切なへの直接の非仮想呼び出しにコンパイラによって最適化されますfoo
。