The C++ compiler creates the vtable for each class. If classes
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,
m4, the vtable will have 4 entries and
m3 will be the third entry in the table. Sub-class
A overrides methods
m4, while sub-class
B overrides them all. The vtable for
A will have four entries, with pointers to
B will also have four entries, with pointers to
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.)