When you have at least one virtual
function in a class, then the compiler creates a single table for the class listing the member function pointers. Consider:
struct Base
{
virtual ~Base() { };
int n_;
};
In pseudo-code you can imagine the compiler adding:
void* Base::__virtual_dispatch_table[] = { (void*)&Base::~Base };
Then, when you have an actual object of type Base
it will have an extra hidden data member that points to the Base::__virtual_dispatch_table
(the "VDT"):
Variable definition Memory layout
------------------- -------------
Base myBase; int n_;
void** __p_vdt = Base::__virtual_dispatch_table;
Now, if you have a Base* p
and delete p;
, the compiler says "hey - it's virtual
- I won't hardcode a call to Base::~Base
, instead I'll generate code that does something like this pseudo-code:
void (Base::*p_destructor) = p->__p_vdt[0]
*p_destructor(p); // "p" will provide the "this" value while the destructor runs
Why would you want to do all that? Because when you come along with a Derived
object...
class Derived: public Base
{
private:
int* m_pnArray;
...
...the compiler can create a separate virtual dispatch table...
void* Derived::__virtual_dispatch_table[] = { (void*)&Derived::~Derived };
...andd lay out the Derived object's memory like this:
Variable definition Memory layout
------------------- -------------
Derived derived; int n_;
void** __p_vdt = Derived::__virtual_dispatch_table;
int* m_pnArray;
Notice that the __p_vdt
is in the same relative location within the object layout, but now points to the Derived
class's virtual dispatch table?
Now, if you create a Base*
to derived
, the exact same code needed to call the destructor for a Base
object, which - in case you've lost track - was...
void (Base::*p_destructor) = p->__p_vdt[0]
*p_destructor(p); // "p" will provide the "this" value while the destructor runs
...can be run but will end up using the Derived
object's __p_vdt
value of Derived::__virtual_dispatch_table
, and finding the Derived
class's destructor.
Derived
object should call theDerived
destructor? Because that's how aDerived
object is supposed to be destroyed. Or are you asking about the mechanism behind it, so that it works correctly with aBase
pointer? It's exactly the same as any other virtual function call. – Leola