My question is basePtr
itself is of type Base
. How is it able to access the vptr
which is present inside the Derived
class?
It's not, it's only accessing its own vptr
, but that vptr
is being modified by Derived
during initialization. In C++ inheritance, the base class is contained in the derived class as a base class subobject.
The layout is as follows:
class Base {
protected:
vtable_t* vptr;
public:
// ...
};
class Derived {
public:
Base BaseSubobject;
// ...
};
// probably passes, if a vtable pointer is as large as void*
static_assert(sizeof(Base) == sizeof(void*));
// will pass on any sane implementation
static_assert(sizeof(Derived) == sizeof(Base));
Notice that Derived
doesn't have its own vptr
, there only one vptr
inside of the BaseSubobject
.
During When Derived
gets initialized, it will first initialize the BaseSubobject
inside, and then mutate the vptr
inside of Base
to become a pointer to the Derived
vtable. The process looks something like this:
// Base constructor sets its vptr to the vtable of Base
Base::Base() : vptr(&Base::vtable) {}
// Derived constructor first initializes Base, then replaces the vptr inside
Derived::Derived() : BaseSubobject() {
// replaces Base::vptr
this->BaseSubobject.vptr = &Derived::vtable;
}
// dynamic dispatch process for virtual void foo():
void Base::__dispatch_to_foo__() {
// step 1: fetch address of virtual function from Base::vptr,
// which may be a pointer to Derived::vtable
void(*foo)(Base*) = this->vptr[__foo_index__];
// step 2: call the fetched address
foo(this);
}
On a side note, this is also why virtual calls won't dispatch to Derived
in the Base
constructor. While Base
is being initialized, its vtable pointer hasn't been replaced by that of Derived
yet.
Disclaimer 1: All uses of types, data members, and constructors are exposition-only. They're just meant to approximate what the compiler generates, and are not equivalent.
Disclaimer 2: vtables are an implementation detail. The C++ standard doesn't require polymorphism to be implemented this way, but most compilers use this technique.