The pointer to the vtable is updated on entry to each constructor in the hierarchy and then again on entry of each destructor. The vptr will start pointing to the base class, and then will be updated as the different levels are initialized.
While you will read from many different people that this is implementation defined, as it is the whole choice of vtables, but the fact is that all compilers use vtables, and once you choose a vtable approach, the standard does mandate that the type of the runtime object is that of the constructor/destructor being executed, and that in turn means that whatever the dynamic dispatch mechanism is, it has to be adjusted as the construction/destruction chain is traversed.
Consider the following code snippet:
#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;
}
The standard mandates that the output of that program is base
, derived
, derived
, base
, but the call in callback
is the same from all the four calls to the function. The only way that it can be implemented is by updating the vptr in the object as construction / destruction progresses.
*this
to a function that takes a reference to your base type, and call from there the virtual function. The dispatch inside that other function must be dynamic, as the compiler does not know who the caller is. – Hair