Monday, June 18, 2007

4.4 Pointer to Member Functions

The value returned from taking the address of a nonstatic data member is the byte value of the member's position in the class layout (plus 1). One can think of it as an incomplete value. It needs to be bound to the address of a class object before an actual instance of the member can be accessed.

The value returned from taking the address of a nonstatic member function, if it is nonvirtual, is the actual address in memory where the text of the function is located. This value, however,equally incomplete. It, too, needs to be bound to the address of a class object before an actual invocation of the member function is possible. The object's address serves as the this pointer argument required by all nonstatic member functions.

The syntax of declaring a pointer-to-member function is: double (Point::* pmf) ();

Example:
double (Point::* coord) = &Point::x; //Point is a class name
coord = &Point::y; //to assign a value to it
(origin.*coord)(); //Invocation uses the pointer-to-member selection operator
(ptr->*coord)();

Supporting pointer-to-virtual-member functions

Taking the address of a virtual member function yields its index into its class's associated virtual table. The compiler must distinguish the type of the two values: an address in memory (a large number) and an index into the virtual table.

cfront implementation:

((int)pmf & ~127)
? //non-virtual invocation
(*pmf)(ptr)
: //virtual invocation
( *ptr->vptr[(int)pmf]) (ptr);

this implementation assumes a limit of 128 virtual functions to an inheritance graph. This is not desirable, but in practice it has proved viable.

Pointer-to-Member Functions under MI

Stroustrup design an aggregate structure:

struct __mptr
{
int delta; // this pointer offset
int index: //virtual table index
union
{
ptrtofunc faddr; // nonvirtual member function address
int v_offset; //location of the vptr of a virtual base class
}
};

original implementation:

(ptr->*pmf)() will be transformed into:
(pmf.index < 0)
? // non-virtual invocation
(*pmf.faddr)(ptr)
: // virtual invocation
(*ptr->vptr[pmf.index])(ptr);

Microsoft, provide the following optimization:

1. A single inheritance instance (which simply holds either the vcall thunk or function address)

2. A multiple inheritance instance (which holds the faddr and delta members)

3. A vitual inheritance instance (which holds four members)

No comments: