1

I read this article: https://shaharmike.com/cpp/vtable-part2/

And I can not understand why in the vtable (at the end of article) we have this pointer:

0x400918 0x400820 non-virtual thunk to Child::FatherFoo()

but not pointer directly to method Child::FatherFoo()?

I assume that Child's vtable is completely separate from Father's vtable.

  • The article explains this very well I think `Here’s the solution: the compiler creates a ‘thunk’ method that corrects this and then calls the ‘real’ method. The address of the thunk method will sit under Child’s Father vtable, while the ‘real’ method will be under Child’s vtable.` This also plays into this sentence `In other words, for a given Child c;: (void*)&c != (void*)static_cast(&c)` which shows you why the `this` pointer needs to be adjusted – PeterT Feb 26 '18 at 21:28
  • when access FatherFool() through Father*, "this" pointer is point to the second vtable in the example. The thunk is mainly used to adjust "this" pointer to the very top of the object, this is a critical step because imaging Child::FatherFoo() can access data member in Mother or Child. – hefeicoder Jul 03 '19 at 17:20

1 Answers1

1

Just like all but one members of a C struct cannot have the same address as the encompassing object, all but one non-empty base class subobjects cannot have the same address as the complete object; a polymorphic base class (one with virtual functions) is not empty by definition.

The polymorphic base subobject that has the same address as the derived object is called the primary base. The derived object shares the base of the vtable layout and the vptr with the primary base: the implicit this parameter is not changed.

Note: The concept of primary base is a C++ implementation domain concept (like vtable, vptr...), not a C++ language concept (like base class, virtual function...). So, obviously, it is not described in the C++ standard.

When a virtual function is called dynamically, via the virtual call mechanism, on a object of an unknown dynamic type, the this implicit argument must be adjusted to the correct value, which is a different value of the non primary bases. The intermediary that does that is called a thunk. In this case, the thunk can do a jump and not a function call, to the correct function: the extra work occurs on function entry, and nothing is needed on function exit.

Another type of adjustment occur when a covariant return type is used and the derived to base relation of the covariant return is not a derived to primary base relation. Obviously this kind of thunk doesn't do a jump, it does a function call, as the adjustment for covariance occurs on function exit.

curiousguy
  • 8,038
  • 2
  • 40
  • 58