How is the information about ptr to a virtual member function vs. non virtual function encoded within a function pointer. Clearly this is compiler dependent, but I would like to understand techniques used to encode this information.
#include <cassert>
struct X {
virtual void f() {
}
void f1() {
}
};
struct Y : X {
void f() {
assert(0); // does trigger
}
};
int main() {
auto ptr = &X::f;
X *p = new Y();
(p->*ptr)();
}
CodePudding user response:
A non-virtual class method is, basically, an ordinary function, so a pointer to a non-virtual class method is functionally equivalent to an ordinary function pointer, the function's address.
Every non-static class method, whether virtual or not, receives an internal pointer. You know it as "this
". This is, typically, an additional, hidden function parameter.
Every class with virtual inheritance has a hidden internal pointer as one of its class members. It's generated by the compiler and the compiler automatically generates the appropriate code to initialize it when an instance of the class gets created. This pointer points to compiler-generated metadata that, amongst other things, records the pointer to the metadata for the instantiated class and what all the real overridden virtual functions are, for that instance of the class.
A pointer to a virtual class method is an address of a function that digs into this
, and uses the this
's virtual function dispatch metadata to look up the actual, instantiated class and then use the hidden pointer to virtual class's metadata to look up the appropriate virtual function override, for this object, then (after a few more bookkeeping procedures) jumps to the appropriate, real, virtual function.
So the address of a virtual function is, typically, also an address of a function, except that it's not any specific virtual function, but rather a compiler-generated function that figures out what "real" object it's being invoked for and its appropriate overridden virtual function.
This is the capsule summary of a typical compiler implementation. Some details have been omitted. There are minor variations that differ from compiler to compiler.
CodePudding user response:
This is what the Itanium C ABI specification says (this of course applies only to Itanium ABI and not to all C implementations in general).
2.3.2 Member Function Pointers
In all representations, the basic ABI properties of member function pointer types are those of the following class, where
fnptr_t
is the appropriate function-pointer type for a member function of this type:struct { fnptr_t ptr; ptrdiff_t adj; };
A member function pointer for a non-virtual member function is represented with
ptr
set to a pointer to the function, using the base ABI's representation of function pointers.In the standard representation, a member function pointer for a virtual function is represented with
ptr
set to 1 plus the function's v-table entry offset (in bytes), converted to a function pointer as if byreinterpret_cast<fnptr_t>(uintfnptr_t(1 offset))
, whereuintfnptr_t
is an unsigned integer of the same size asfnptr_t
.In both of these cases,
adj
stores the offset (in bytes) which must be added to the this pointer before the call.