As with any pointer, we declare a pointer to member using a *
to indicate that the name we’re declaring is a pointer. Unlike ordinary pointers, a pointer to member also incorporates the class that contains the member. Hence, we must precede the *
with classname::
to indicate that the pointer we are defining can point to a member of classname. For example:
// pdata can point to a string member of a const (or non const) Screen object
const string Screen::*pdata;
declares that pdata
is a “pointer to a member of class Screen
that has type const string
.” The data members in a const
object are themselves const
. By making our pointer a pointer to const string
member, we say that we can use pdata
to point to a member of any Screen
object, const
or not. In exchange we can use pdata
to read, but not write to, the member to which it points.
When we initialize (or assign to) a pointer to member, we say to which member it points. For example, we can make pdata
point to the contents
member of an unspecified Screen
object as follows:
pdata = &Screen::contents;
Here, we apply the address-of operator not to an object in memory but to a member of the class Screen
.
Of course, under the new standard, the easiest way to declare a pointer to member is to use auto
or decltype
:
auto pdata = &Screen::contents;
It is essential to understand that when we initialize or assign a pointer to member, that pointer does not yet point to any data. It identifies a specific member but not the object that contains that member. We supply the object when we dereference the pointer to member.
Analogous to the member access operators, .
and ->
, there are two pointer-to-member access operators, .*
and ->*
, that let us supply an object and dereference the pointer to fetch a member of that object:
Screen myScreen, *pScreen = &myScreen;
// .* dereferences pdata to fetch the contents member from the object myScreen
auto s = myScreen.*pdata;
// ->* dereferences pdata to fetch contents from the object to which pScreen points
s = pScreen->*pdata;
Conceptually, these operators perform two actions: They dereference the pointer to member to get the member that we want; then, like the member access operators, they fetch that member from an object (.*
) or through a pointer (->*
).
Normal access controls apply to pointers to members. For example, the contents
member of Screen
is private
. As a result, the use of pdata
above must have been inside a member or friend of class Screen
or it would be an error.
Because data members are typically private
, we normally can’t get a pointer to data member directly. Instead, if a class like Screen
wanted to allow access to its contents
member, it would define a function to return a pointer to that member:
class Screen {
public:
// data is a static member that returns a pointer to member
static const std::string Screen::*data()
{ return &Screen::contents; }
// other members as before
};
Here we’ve added a static
member to class Screen
that returns a pointer to the contents
member of a Screen
. The return type of this function is the same type as our original pdata
pointer. Reading the return type from right to left, we see that data
returns a pointer to a member of class Screen
that is a string
that is const
. The body of the function applies the address-of operator to the contents
member, so the function returns a pointer to the contents
member of Screen
.
When we call data
, we get a pointer to member:
// data() returns a pointer to the contents member of class Screen
const string Screen::*pdata = Screen::data();
As before, pdata
points to a member of class Screen
but not to actual data. To use pdata
, we must bind it to an object of type Screen
// fetch the contents of the object named myScreen
auto s = myScreen.*pdata;
Exercise 19.11: What is the difference between an ordinary data pointer and a pointer to a data member?
Exercise 19.12: Define a pointer to member that can point to the cursor
member of class Screen
. Fetch the value of Screen::cursor
through that pointer.
Exercise 19.13: Define the type that can represent a pointer to the bookNo
member of the Sales_data
class.