Developer

Don't be overwhelmed when implementing pointers to member functions

Pointers to member functions are complex to write, but they are essential elements in multithreaded C++ applications. Find out how to create them and use them in callbacks.


Pointers to members are among the most intricate syntactic constructs in C++. Nevertheless, they're indispensable in event-driven and multithreaded environments where callback functions are employed extensively. In multithreaded applications, each thread invokes a member function through a pointer to the member. The development of such applications in C++ would have been extremely difficult without the existence of pointers to members.

You might be put off by the syntax at first blush, but you will find that it’s consistent and can be easily simplified by using proper typedef declarations. I will walk you through the process of declaring pointers to member functions, assigning a value to them, and using them to implement callbacks.

Declarations of pointers to member functions
A pointer to a member function contains the member function's return type, the class name followed by ::, the pointer's name, and the function's parameter list. Although the syntax might seem confusing at first, it resembles the form of pointers to ordinary functions, with the addition of the class name followed by the operator :: before the asterisk. A pointer to an external function might be declared like this:
void (*pf)(char *, const char *);
void strcpy(char * dest, const char * source);
pf=strcpy;


And a corresponding pointer to a member function of class A would look like this:
void (A::*pmf)(char *, const char *);

If you parse this declaration, pmf is a pointer to a member function of class A that returns no value and takes two arguments of type char * and const char *. Notice that except for the additional A:: before the asterisk, this declaration is identical to the previous one.

Assigning a value
To assign a value to a pointer to a member, you take the member function’s qualified name and precede it with an ampersand. See Listing A for a code example. Although some outdated compilers will still work if you omit the ampersand, it’s mandatory in standard C++.

Using a typedef
You can use a typedef to hide the obfuscated syntax of pointers to members. For example, the following statement defines PMA as a synonym for a pointer to a member function of class A that returns no value and takes char * and const char *:
typedef void(A::*PMA)(char *, const char *);
PMA pmf= &A::strcat; // use a typedef to define a pointer to member


The use of a typedef is particularly useful for declaring arrays of pointers to members, as we will see shortly.

Invoking a member function through a pointer to a member
The use of a pointer to a member function enables you to call a member function of an object without needing to know that function’s name. For example, a dispatcher function that takes pmf as an argument and uses it to invoke a function doesn’t care whether it’s pointing to strcpy() or strcat(). Yet there is a crucial difference between ordinary pointers to external functions and pointers to member functions. When using the latter, you must refer to the specific object on which the member function is called. Therefore, you need to have a valid object or a pointer to an object in addition to a pointer to a member.

To clarify this point, let's look at an example. Suppose you have two object instances of class A, as shown in Listing B. Pointers to member functions respect polymorphism. Thus, if you call a virtual member function through such a pointer, the call will be resolved dynamically. Note, however, that you can't take the address of a class's constructor(s) and destructor(s).

Advanced implementations
Now that you are familiar with the basics, let’s look at some of the more advanced techniques and uses of pointers to member functions.

Arrays of pointers to members
In the following example, I declare an array of two pointers to members and assign the addresses of A’s member functions to them:
PMA pmf[2]= {&A::strcpy, &A::strcat};

Such arrays are useful in menu-driven applications, where the user clicks on an option and the application in return invokes the matching callback function, as shown in Listing C.

Const member functions
The type of a pointer to a member consists of the member function’s signature and that member’s const/volatile qualification. pmf may point to any member function with a matching signature of class A as long as that member function isn’t const. Therefore, if you attempt to assign to pmf the address of touppercase(), you will receive a compilation error because touppercase() is const. Check out Listing D for an example.

Note that certain buggy compilers will allow you to assign a non-const pointer to a const member function, but this behavior doesn’t comply with the C++ standard.

Conclusion
It might surprise you, but pointers to members aren’t real pointers. Whereas a classic pointer is implemented as an integer that holds a memory address of a certain variable or a function, a pointer to a member is implemented as a complex data structure that contains several data members. This complexity may be a little daunting at first, but once you get used to the syntax, you'll find that pointers to members are indispensable when you're using a lot of callback functions in event-driven and multithreaded environments.

Editor's Picks