You should first notice that a C ++ method can be implemented (and usually implemented) just like a regular function that takes an additional hidden parameter in front of all other parameters called this .
In other words, in
struct P2d { double x, y; void doIt(int a, double b) { ... } };
the machine code for doIt the same that would be generated by the C compiler for
void P2d$vid$doIt(P2d *this, int a, double b) { ... }
and a call like p->doIt(10, 3.14) compiled into P2d$vid$doIt(p, 10, 3.14);
Given this, a method pointer for a simple class that does not have virtual methods can be implemented as a regular pointer to the method code (NOTE: I use vid for "Void of Int + Double" as a toy example of a "name change" that C ++ compilers make for handling overloads - different functions with the same name, but with different parameters).
If the class has virtual methods, this is no longer the case.
Most C ++ compilers implement virtual dispatch with the rejection of VMT ... i.e. in
struct P2d { ... virtual void doIt(int a, double b); };
the code to call like p->doIt(10, 3.14) , where p is P2d * , is the same as the C compiler generates for
(p->$VMTab.vid$doIt)(p, 10, 3.14);
i.e. the instance contains a hidden pointer to a virtual method table, which for each member contains an effective code address (provided that the compiler cannot conclude that the class p really P2d and is not derived, since in this case the call may be the same as for a non-virtual method).
Method pointers must respect virtual methods ... i.e. calling doIt indirectly using a method pointer on an instance derived from P2d is required to invoke the derived version, while the same method pointer instead refers to the base version when used in P2d instances. This means that the choice of code to call depends on both the pointer and the class instance.
A possible implementation is the use of a trampoline:
void MethodPointerCallerForP2dDoit(P2d *p, int a, double b) { p->doIt(a, b); }
and in this case, the method pointer still remains only a pointer to the code (but to the trampoline, and not to the final method).
An alternative would be to save the method inside the VMT as a pointer to an index method. This would be possible because in C ++ the method pointer is bound to a particular class, and therefore the compiler knows whether virtual methods exist for this class or not.
Multiple inheritance does not complicate things for method pointers, because at compile time you can just allow everything to only one VMT destination table.