Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Pointers to Members

Last updated Jan 1, 2003.

If you’re looking for more up-to-date information on this topic, please visit our C/C++ Programming article, podcast, and store pages.

Pointers to members are similar to ordinary pointers to functions, in that they enable you to call a member function without knowing its name. Yet, unlike ordinary pointers to functions, they also enable you to manipulate data members of an object. In the following passages, I will discuss pointers to members in further detail and show how to define and use them.

Pointers to Member Functions and Pointers to Data Members

A class can have two general categories of members: functions and data members. Similarly, there are two categories of pointers to members: pointers to member functions, and pointers to data members. The latter are less common because you rarely have direct access to data members. However, when using legacy C code with structs or classes have public data members, pointers to data members might be useful.

Declaring Pointers to Data Members

The syntax of pointers to members might look confusing at first, but it's consistent. The syntax resembles the form of ordinary pointers to functions, with the addition of the class name followed by the operator ::. For example, if an ordinary pointer to int looks like this:

int * pi; 

you define a pointer to an int member of class A like this:

class A{/**/};
int A::*pmi; // pmi is a pointer to an int member of A

You can initialize pmi like this:

class A
{
public:
 int num;
 int x;
};
int A::*pmi = &A::num; // 1

Manipulating a data member through an object

The statement numbered 1 defines a pointer to an int member of class A and initializes it with the address of num. Now you can use the pointer pmi to examine and modify num's value in any object of class A:

A a1;
A a2;
int n = a1.*pmi; // copy the value of a1.num to n
a1.*pmi = 5; // assign the value to a1.num 
a2.*pmi = 6; // assign the value 6 to a2.num 

Manipulating a data member through an object's pointer

Similarly, you can access a data member through a pointer to A like this:

A * pa = new A;
int n = pa->*pmi; // assign to n the value of pa->num 
pa->*pmi = 5; // assign the value 5 to pa->num 

Or using a pointer to an object derived from A:

class D : public A {};
A* pd = new D;
pd->*pmi = 5; // assign the value 5 to pd->num

Declaring Pointers to Member Functions

Thus far, I've focused on pointers to data members, which are used less often than pointers to member functions. A pointer to a member function consists of the member function's return type, the class name followed by ::, the pointer's name, and the function's parameter list. For example, a pointer to a member function of class A that returns int and takes no arguments looks like this (note that both pairs of parentheses are mandatory):

class A 
{
public:
 int func (); 
};

int (A::*pmf) (); /* pmf is a pointer to some member 
function of class A that returns int and takes no 
arguments*/

In fact, a pointer to a member function looks just like an ordinary pointer to function, except that it also contains the class's name immediately followed by the :: operator. You can invoke the member function to which pmf points like this:

pmf = &A::func; //assign pmf
A a;
A *pa = &a;
(a.*pmf)(); // invoke a.func() 
// call through a pointer to an object
(pa->*pmf)(); // calls pa->func()

Pointers to member functions respect polymorphism; if you call a virtual member function through a pointer to member, the call will be resolved dynamically as the following code shows:

class Base
{
public:
 virtual int f (int n);
};
class Derived : public Base {
public:
 int f (int h); //override
};
Base *pb = new Derived;
int (Base::*pmf)(int) = &Base::f;
(pb->*pmf)(5); // call resolved as D::f(5);

Note that you cannot take the address of constructors and destructors.

The Underlying Representation of Pointers to Members

Although pointers to members behave like ordinary pointers, behind the scenes their representation is quite different. In fact, a pointer to member usually consists of a struct containing up to four fields in certain cases. This is because pointers to members have to support not only ordinary member functions, but also virtual member functions, member functions of objects that have multiple base classes, and member functions of virtual base classes. Thus, the simplest member function can be represented as a set of two pointers: one holding the physical memory address of the member function, and a second pointer that holds the this pointer. However, in cases like a virtual member function, multiple inheritance and virtual inheritance, the pointer to member must store additional information. Therefore, you can't cast pointers to members to ordinary pointers nor can you safely cast between pointers to members of different types.

To get a notion of how your compiler represents pointers to members, use the sizeof operator. In the following example, the sizes of a pointer to data member and a pointer to a member function are taken. As you can see, they have different sizes, hence, different representations:

struct A
{
 int x;
 void f();
};
int A::*pmi = &A::x;
void (A::*pmf)() = &A::f;
int n = sizeof (pmi); // 8 byte with my compiler
int m = sizeof (pmf); // 12 bytes with my compiler

Note that each of these pointers may have a different representation, depending on the class in question and whether the member function is virtual.

Summary

Pointers to members are the third component in the trilogy of function callback constructs. The other two are pointers to functions and function objects. In the next revision of C++, a new library facility called function will provide a homogeneous interface to abstract the syntactic and technical differences among these three constructs, enabling the user to treat them in a uniform fashion.

One common mistake made by novices is attempting to invoke a member function through a pointer to member alone. Remember that a pointer itself isn't enough; you also need an object on which the function will be called. Thus, you need to use both an object (or a pointer to an object) and a pointer to a member function to perform the call. In this regard, a pointer to a member differs from ordinary pointers to functions. Think of it as an offset inside a class to the member in question, rather than a physical memory address.