Pointers to members
A pointer is a variable that holds the
address of some location. You can change what a pointer selects at runtime, and
the destination of the pointer can be either data or a function. The C++
pointer-to-member follows this same concept, except that what it selects
is a location inside a class. The dilemma here is that a pointer needs an
address, but there is no “address” inside a class; selecting a
member of a class means offsetting into that class. You can’t produce an
actual address until you combine that offset with the starting address of a
particular object. The syntax of pointers to members requires that you select an
object at the same time you’re dereferencing the pointer to
member.
To understand this syntax, consider a
simple structure, with a pointer sp and an object so for this
structure. You can select members with the syntax shown:
//: C11:SimpleStructure.cpp
struct Simple { int a; };
int main() {
Simple so, *sp = &so;
sp->a;
so.a;
} ///:~
Now suppose you have an ordinary pointer
to an integer, ip. To access what ip is pointing to, you
dereference the pointer with a ‘*’:
*ip = 4;
Finally, consider what happens if you
have a pointer that happens to point to something inside a class object, even if
it does in fact represent an offset into the object. To access what it’s
pointing at, you must dereference it with *. But it’s an offset
into an object, so you must also refer to that particular object. Thus, the
* is combined with the object dereference. So the new syntax
becomes –>* for a pointer to an object,
and .* for the object or a reference, like
this:
objectPointer->*pointerToMember = 47;
object.*pointerToMember = 47;
Now, what is the syntax for defining
pointerToMember? Like any pointer, you have to say what type it’s
pointing at, and you use a * in the definition. The only difference is
that you must say what class of objects this pointer-to-member is used with. Of
course, this is accomplished with the name of the class and the scope resolution
operator. Thus,
int ObjectClass::*pointerToMember;
defines a pointer-to-member variable
called pointerToMember that points to any int inside
ObjectClass. You can also initialize the pointer-to-member when you
define it (or at any other time):
int ObjectClass::*pointerToMember = &ObjectClass::a;
There is actually no
“address” of ObjectClass::a because you’re just
referring to the class and not an object of that class. Thus,
&ObjectClass::a can be used only as pointer-to-member
syntax.
Here’s an example that shows how to
create and use pointers to data members:
//: C11:PointerToMemberData.cpp
#include <iostream>
using namespace std;
class Data {
public:
int a, b, c;
void print() const {
cout << "a = " << a << ", b = " << b
<< ", c = " << c << endl;
}
};
int main() {
Data d, *dp = &d;
int Data::*pmInt = &Data::a;
dp->*pmInt = 47;
pmInt = &Data::b;
d.*pmInt = 48;
pmInt = &Data::c;
dp->*pmInt = 49;
dp->print();
} ///:~
Obviously, these are too awkward to use
anywhere except for special cases (which is exactly what they were intended
for).
Also, pointers to members are quite
limited: they can be assigned only to a specific location inside a class. You
could not, for example, increment or compare them as you can with ordinary
pointers.