Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is pointer to member function implemented in C++?

The pointer to member function in c++ is in three parts:

Offset
Address/index
virtual?

Offset is used for Pointer adjustment when derived object is called using base pointer.

How is this offset implemented? Is it pointer to some table, one table for each derived class and the table contains entries of the form (base X, offset)?

Also, where can I get more info about this?

like image 837
q126y Avatar asked Dec 19 '15 04:12

q126y


1 Answers

First you should note that a C++ method can be implemented (and is normally implemented) just as a regular function that accepts an extra hidden parameter before all other parameters, named this.

In other words in

struct P2d {
   double x, y;
   void doIt(int a, double b) {
       ...
   }
};

the machine code for doIt is the same that would be generated by a C compiler for

void P2d$vid$doIt(P2d *this, int a, double b) {
    ...
}

and a call like p->doIt(10, 3.14) is compiled to P2d$vid$doIt(p, 10, 3.14);

Given this a method pointer for a simple class that has no virtual methods can be implemented as a regular pointer to the method code (NOTE: I'm using vid for "Void of Int+Double" as a toy example of the "name mangling" that C++ compilers do to handle overloads - different functions with the same name but different parameters).

If the class has virtual methods however this is no more true.

Most C++ compilers implement virtual dispatching unsing a VMT... i.e. in

struct P2d {
    ...
    virtual void doIt(int a, double b);
};

the code for a call like p->doIt(10, 3.14) where p is a P2d * is the same that a C compiler would generate for

(p->$VMTab.vid$doIt)(p, 10, 3.14);

i.e. the instance contains a hidden pointer to a virtual method table that for each member contains the effective code address (assuming the compiler cannot infer that the class of p is indeed P2d and not a derived, as in that case the call can be the same as for a non-virtual method).

Method pointers are required to respect virtual methods... i.e. calling doIt indirectly using a method pointer on an instance derived from P2d is required to call the derived version while the same method pointer is instead to call the base version when used on P2d instances. This means the selection of which code to call depends on both the pointer and the class instance.

A possible implementation is using a trampoline:

void MethodPointerCallerForP2dDoit(P2d *p, int a, double b) {
    p->doIt(a, b);
}

and in this case a method pointer is still just pointer to code (but to the trampoline, not to the final method).

An alternative would be to store as method pointer the index of the method inside the VMT instead. This would be feasible because in C++ the method pointer is tied to a specific class and therefore the compiler knows if for that class there are virtual methods or not.

Multiple inheritance do not complicate things for method pointers because everything can be just resolved to a single final VMT table at compile time.

like image 175
6502 Avatar answered Nov 13 '22 10:11

6502