The C++ compiler creates the vtable for each class. If classes A
and B
both are sub-classes of class Base
, and override methods in base, then the vtable for A and the vtable for B are constructed with pointers to the respective overridden methods.
For the code where the virtual method is called, the entry in the vtable for the object is loaded with the address of the correct method for the sub-class.
Assuming that class Base
has four virtual methods, m1
, m2
, m3
, and m4
, the vtable will have 4 entries and m3
will be the third entry in the table. Sub-class A
overrides methods m1
and m4
, while sub-class B
overrides them all. The vtable for A
will have four entries, with pointers to A::m1
, Base::m2
, Base:m3
, and A::m4
, while B
will also have four entries, with pointers to B::m1
, B::m2
, B::m3
, and B::m4
. At the call site where m3
is being invoked, the third vtable entry is loaded with the correct method pointer because the compiler constructed the tables this way.
(Of course, there is much more to vtable construction and layout than I have presented, so your mileage may vary.)