- Table of Contents
- Previous Chapter
- Next Chapter

# Chapter 16: Classes Having Pointers To Members

Classes having `pointer data members` have been discussed in detail in chapter 9. Classes defining pointer data-members deserve some special attention, as they usually require the definitions of copy constructors, overloaded assignment operators and destructors

Situations exist where we do not need a pointer to an object but rather a pointer to members of a class. Pointers to members can profitably be used to configure the behavior of objects of classes. Depending on which member a pointer to a member points to objects will show certain behavior.

Although pointers to members have their use, polymorphism can frequently be used to realize comparable behavior. Consider a class having a member `process` performing one of a series of alternate behaviors. Instead of selecting the behavior of choice at object construction time the class could use the interface of some (abstract) base class, passing an object of some derived class to its constructor and could thus configure its behavior. This allows for easy, extensible and flexible configuration, but access to the class's data members would be less flexible and would possibly require the use of `friend' declarations. In such cases pointers to members may actually be preferred as this allows for (somewhat less flexible) configuration as well as direct access to a class's data members.

So the choice apparently is between on the one hand ease of configuration and on the other hand ease of access to a class's data members. In this chapter we'll concentrate on pointers to members, investigating what these pointers have to offer.

## 16.1: Pointers to members: an example

Knowing how pointers to variables and objects are used does not intuitively lead to the concept of pointers to members . Even if the return types and parameter types of member functions are taken into account, surprises can easily be encountered. For example, consider the following class:

        class String
        {
            char const *(*d_sp)() const;

            public:
                char const *get() const;
        };

For this class, it is not possible to let `char const *(*d_sp)() const` point to the `String::get` member function as `d_sp` cannot be given the address of the member function `get`.

One of the reasons why this doesn't work is that the variable `d_sp` has global scope (it is a pointer to a function, not a pointer to a function within `String`), while the member function `get` is defined within the `String` class, and thus has `class scope`. The fact that `d_sp` is a data member of the class `String` is irrelevant here. According to `d_sp`'s definition, it points to a function living somewhere outside of the class.

Consequently, to define a pointer to a member (either data or function, but usually a function) of a class, the scope of the pointer must indicate class scope. Doing so, a pointer to the member `String::get` is defined like this:

        char const *(String::*d_sp)() const;

So, by prefixing the `*d_sp` pointer data member by `String::`, it is defined as a pointer in the context of the class `String`. According to its definition it is a pointer to a function in the class `String`, not expecting arguments, not modifying its object's data, and returning a pointer to constant characters.

## 16.2: Defining pointers to members

Pointers to members are defined by prefixing the normal pointer notation with the appropriate class plus scope resolution operator. Therefore, in the previous section, we used `char const * (String::*d_sp)() const` to indicate that `d_sp`

- is a pointer (`*d_sp`);
- points to something in the class `String` (`String::*d_sp`);
- is a pointer to a `const` function, returning a `char const *` (`char const * (String::*d_sp)() const`).

The prototype of a matching function is therefore:

        char const *String::somefun() const;

which is any `const` parameterless function in the class `String`, returning a `char const *`.

When defining pointers to members the standard procedure for constructing pointers to functions can still be applied:

- put parentheses around the fully qualified function name (i.e., the function's header, including the function's class name):

      char const * ( String::somefun ) () const

- Put a pointer (a star (`*`)) character immediately before the function name itself:

      char const * ( String:: * somefun ) () const

- Replace the function name with the name of the pointer variable:

      char const * (String::*d_sp)() const

Here is another example, defining a pointer to a data member. Assume the class `String` contains a `string d_text` member. How to construct a pointer to this member? Again we follow standard procedure:

- put parentheses around the fully qualified variable name:

      std::string (String::d_text)

- Put a pointer (a star (`*`)) character immediately before the variable-name itself:

      std::string (String::*d_text)

- Replace the variable name with the name of the pointer variable:

      std::string (String::*tp)

  In this case, the parentheses are superfluous and may be omitted:

      string String::*tp

Alternatively, a very simple rule of thumb is

- Define a normal (i.e., global) pointer variable,
- Prefix the class name to the pointer character, once you point to something inside a class

For example, the following pointer to a global function

        char const * (*sp)() const;

becomes a pointer to a member function after prefixing the class-scope:

        char const * (String::*sp)() const;

Nothing forces us to define pointers to members in their target (`String`) classes. Pointers to members may be defined in their target classes (so they become data members), or in another class, or as a local variable or as a global variable. In all these cases the pointer to member variable can be given the address of the kind of member it points to. The important part is that a pointer to member can be initialized or assigned without requiring the existence of an object of the pointer's target class.

Initializing or assigning an address to such a pointer merely indicates to which member the pointer points. This can be considered some kind of relative address; relative to the object for which the function is called. No object is required when pointers to members are initialized or assigned. While it is allowed to initialize or assign a pointer to member, it is (of course) not possible to call those members without specifying an object of the correct type.

In the following example initialization of and assignment to pointers to members is illustrated (for illustration purposes all members of the class `PointerDemo` are defined `public`). In the example itself the `&`-operator is used to determine the addresses of the members. These operators as well as the class-scopes are required. Even when used inside member implementations:

        #include <cstddef>

        class PointerDemo
        {
            public:
                size_t d_value;
                size_t get() const;
        };

        inline size_t PointerDemo::get() const
        {
            return d_value;
        }

        int main()
        {                                           // initialization
            size_t (PointerDemo::*getPtr)() const = &PointerDemo::get;
            size_t PointerDemo::*valuePtr         = &PointerDemo::d_value;

            getPtr   = &PointerDemo::get;           // assignment
            valuePtr = &PointerDemo::d_value;
        }

This involves nothing special. The difference with pointers at global scope is that we're now restricting ourselves to the scope of the `PointerDemo` class. Because of this restriction, all pointer definitions and all variables whose addresses are used must be given the `PointerDemo` class scope.

Pointers to members can also be used with `virtual` member functions. No special syntax is required when pointing to virtual members. Pointer construction, initialization and assignment is done identically to the way it is done with non-virtual members.

## 16.3: Using pointers to members

Using pointers to members to call a member function requires the existence of an object of the class of the members to which the pointer to member refers to. With pointers operating at global scope, the dereferencing operator `*` is used. With pointers to objects the field selector operator operating on pointers (`->`) or the field selector operating operating on objects (`.`) can be used to select appropriate members.

To use a pointer to member in combination with an object the pointer to member field selector (`.*`) must be specified. To use a pointer to a member via a pointer to an object the `pointer to member field selector through a pointer to an object' (`->*`) must be specified. These two operators combine the notions of a field selection (the `.` and `->` parts) to reach the appropriate field in an object and of dereferencing: a dereference operation is used to reach the function or variable the pointer to member points to.

Using the example from the previous section, let's see how we can use pointers to member functions and pointers to data members:

        #include <iostream>

        class PointerDemo
        {
            public:
                size_t d_value;
                size_t get() const;
        };

        inline size_t PointerDemo::get() const
        {
            return d_value;
        }

        using namespace std;

        int main()
        {                                           // initialization
            size_t (PointerDemo::*getPtr)() const = &PointerDemo::get;
            size_t PointerDemo::*valuePtr   = &PointerDemo::d_value;

            PointerDemo object;                     // (1) (see text)
            PointerDemo *ptr = &object;

            object.*valuePtr = 12345;               // (2)
            cout << object.*valuePtr << '\n' <<
                    object.d_value << '\n';

            ptr->*valuePtr = 54321;                 // (3)
            cout << object.d_value << '\n' <<
                    (object.*getPtr)() << '\n' <<   // (4)
                    (ptr->*getPtr)() << '\n';
        }

We note:

- At (1) a `PointerDemo` object and (in the next line) a pointer to such an object is defined.
- At (2) we specify an object (and hence the `.*` operator) to reach the member `valuePtr` points to. This member is given a value.
- At (3) the same member is assigned another value, but this time using the pointer to a `PointerDemo` object. Hence we use the `->*` operator.
- At (4) the `.*` and `->*` are used once again, this time to call a function through a pointer to member. As the function argument list has a higher priority than the pointer to member field selector operator, the latter must be protected by parentheses.

Pointers to members can be used profitably in situations where a class has a member that behaves differently depending on a configuration setting. Consider once again the class `Person` from section 9.3. `Person` defines data members holding a person's name, address and phone number. Assume we want to construct a `Person` database of employees. The employee database can be queried, but depending on the kind of person querying the database either the name, the name and phone number or all stored information about the person is made available. This implies that a member function like `address` must return something like ``<not available>`' in cases where the person querying the database is not allowed to see the person's address, and the actual address in other cases.

The employee database is opened specifying an argument reflecting the status of the employee who wants to make some queries. The status could reflect his or her position in the organization, like `BOARD`, `SUPERVISOR`, `SALESPERSON`, or `CLERK`. The first two categories are allowed to see all information about the employees, a `SALESPERSON` is allowed to see the employee's phone numbers, while the `CLERK` is only allowed to verify whether a person is actually a member of the organization.

We now construct a member `string personInfo(char const *name)` in the database class. A standard implementation of this class could be:

        string PersonData::personInfo(char const *name)
        {
            Person *p = lookup(name);   // see if `name' exists

            if (!p)
                return "not found";

            switch (d_category)
            {
                case BOARD:
                case SUPERVISOR:
                    return allInfo(p);
                case SALESPERSON:
                    return noPhone(p);
                case CLERK:
                    return nameOnly(p);
            }
        }

Although it doesn't take much time, the `switch` must nonetheless be evaluated every time `personInfo` is called. Instead of using a switch, we could define a member `d_infoPtr` as a pointer to a member function of the class `PersonData` returning a `string` and expecting a pointer to a `Person` as its argument.

Instead of evaluating the switch this pointer can be used to point to `allInfo`, `noPhone` or `nameOnly`. Furthermore, the member function the pointer points to will be known by the time the `PersonData` object is constructed and so its value needs to be determined only once (at the PersonData object's construction time).

Having initialized `d_infoPtr` the `personInfo` member function is now implemented simply as:

        string PersonData::personInfo(char const *name)
        {
            Person *p = lookup(name);       // see if `name' exists

            return p ? (this->*d_infoPtr)(p) :  "not found";
        }

The member `d_infoPtr` is defined as follows (within the class `PersonData`, omitting other members):

        class PersonData
        {
            std::string (PersonData::*d_infoPtr)(Person *p);
        };

Finally, the constructor initializes `d_infoPtr`. This could be realized using a simple switch:

        PersonData::PersonData(PersonData::EmployeeCategory cat)
        {
            switch (cat)
            {
                case BOARD:
                case SUPERVISOR:
                    d_infoPtr = &PersonData::allInfo;
                break;
                case SALESPERSON:
                    d_infoPtr = &PersonData::noPhone;
                break;
                case CLERK:
                    d_infoPtr = &PersonData::nameOnly;
                break;
            }
        }

Note how addresses of member functions are determined. The class `PersonData` scope must be specified, even though we're already inside a member function of the class `PersonData`.

Since the `EmployeeCategory` values are known, the `switch` in the above constructor can also easily be avoided by defining a static array of pointers to functions. The class `PersonData` defines the static array:

        class PersonData
        {
            std::string (PersonData::*d_infoPtr)(Person *p);
            static std::string (PersonData::*s_infoPtr[])(Person *p);
        };

and `s_infoPtr[]` can be initialized compile-time:

        string (PersonData::*PersonData::s_infoPtr[])(Person *p) =
        {
            &PersonData::allInfo,       // BOARD
            &PersonData::allInfo,       // SUPERVISOR
            &PersonData::noPhone,       // SALESPERSON
            &PersonData::nameOnly       // CLERK
        };

The constructor, instead of using a `switch`, now directly calls the required member from the appropriate array element:

        PersonData::PersonData(PersonData::EmployeeCategory cat)
        :
            d_infoPtr(s_infoPtr[cat])
        {}

An example using pointers to data members is provided in section 19.1.54, in the context of the `stable_sort` generic algorithm.

## 16.4: Pointers to static members

Static members of a class can be used without having available an object of their class. Public static members can be called like free functions, albeit that their class names must be specified when they are called.

Assume a class `String` has a public static member function `count`, returning the number of string objects created so far. Then, without using any `String` object the function `String::count` may be called:

        void fun()
        {
            cout << String::count() << '\n';
        }

Public static members can be called like free functions (but see also section 8.2.1). Private static members can only be called within the context of their class, by their class's member or friend functions.

Since static members have no associated objects their addresses can be stored in ordinary function pointer variables, operating at the global level. Pointers to members cannot be used to store addresses of static members. Example:

        void fun()
        {
            size_t (*pf)() = String::count;
                    // initialize pf with the address of a static member function

            cout << (*pf)() << '\n';
                    // displays the value returned by String::count()
        }

## 16.5: Pointer sizes

An interesting characteristic of pointers to members is that their sizes differ from those of `normal' pointers. Consider the following little program:

        #include <string>
        #include <iostream>

        class X
        {
            public:
                void fun();
                std::string d_str;
        };
        inline void X::fun()
        {
            std::cout << "hello\n";
        }

        using namespace std;
        int main()
        {
            cout <<
               "size of pointer to data-member:     " << sizeof(&X::d_str) << "\n"
               "size of pointer to member function: " << sizeof(&X::fun) << "\n"
               "size of pointer to non-member data: " << sizeof(char *) << "\n"
               "size of pointer to free function:   " << sizeof(&printf) << '\n';
        }

        /*
            generated output (on 32-bit architectures):

            size of pointer to data-member:     4
            size of pointer to member function: 8
            size of pointer to non-member data: 4
            size of pointer to free function:   4
        */

On a 32-bit architecture a pointer to a member function requires eight bytes, whereas other kind of pointers require four bytes (Using GNU's g++ compiler).

Pointer sizes are hardly ever explicitly used, but their sizes may cause confusion in statements like:

        printf("%p", &X::fun);

Of course, `printf` is likely not the right tool for displaying the value of these C++ specific pointers. The values of these pointers can be inserted into streams when a `union`, reinterpreting the 8-byte pointers as a series of size_t `char` values, is used:

        #include <string>
        #include <iostream>
        #include <iomanip>

        class X
        {
            public:
                void fun();
                std::string d_str;
        };
        inline void X::fun()
        {
            std::cout << "hello\n";
        }

        using namespace std;
        int main()
        {
            union
            {
                void (X::*f)();
                unsigned char *cp;
            }
                u = { &X::fun };

            cout.fill('0');
            cout << hex;
            for (unsigned idx = sizeof(void (X::*)()); idx-- > 0; )
                cout << setw(2) << static_cast<unsigned>(u.cp[idx]);
            cout << '\n';
        }

But why are their sizes different from the sizes of ordinary pointers? To answer this question let's first have a look at the familiar `std::fstream`. It is derived from `std::ifstream` and `std::ofstream`. An `fstream`, therefore, contains both an `ifstream` and an `ofstream`. An `fstream` will be organized as shown in figure 24.

Figure 24: std::fstream object organization

In `fstream (a)` the first base class was `std::istream`, and the second baseclass was `std::ofstream`. But it could also very well be the other way around, as illustrated in `fstream (b)`: first the `std::ofstream`, then the `std::ifstream`. And that's the crux of the biscuit.

If we have an `fstream fstr{"myfile"}` object and do `fstr.seekg(0)`, then we call `ifstream's seekg` function. But if we do `fstr.seekp(0)`, then we call `ofstream's seekp` function. These functions have their own addresses, say &seekg and &seekp. But when we call a member function (like `fstr.seekp(0)`) then what we in fact are doing is `seekp(&fstr, 0)`.

But the problem here is that `&fstr` does not represent the correct object address: `seekp` operates on an `ofstream`, and that object does not start at `&fstr`, so (in `fstream (a)`), at `&(fstr + sizeof(ifstream))`.

So, the compiler, when calling a member function of a class using inheritance, must make a correction for the relative location of an object whose members we are calling.

However, when we're defining something like

        ostream &(fstream::*ptr)(ios::off_type step, ios::seekdir org) = &seekp;

and then do `(fstr->*)ptr(0)` the compiler doesn't know anymore which function is actually being called: it merely receives the function's address. To solve the compiler's problem the shift (for the location of the ofstream object) is now stored in the member pointer itself. That's one reason why the extra data field is needed when using function pointers.

Here is a concrete illustration: first we define 2 structs, each having a member function (all inline, using single line implementations to save some space):

        struct A
        {
            int a;
        };

        struct B
        {
            int b;
            void bfun() {}
        };

Then we define C, which is derived from both A (first) and B (next) (comparable to `fstream`, which embeds `ifstream` and `ofstream`):

        struct C: public A, public B
        {};

Next, in `main` we define objects of two different unions and assign the address of `B::bfun` to their `ptr` fields, but `BPTR.ptr` looks at it as a member in the `struct B` world, while `CPTR.ptr` looks at it as a member in the `struct C` world.

Once the unions' pointer fields have been assigned their value[] arrays are used to display the content of the ptr fields (see below):

        int main()
        {
            union BPTR
            {
                void (B::*ptr)();
                unsigned long value[2];
            };
            BPTR bp;
            bp.ptr = &B::bfun;
            cout << hex << bp.value[0] << ' ' << bp.value[1] << dec << '\n';

            union CPTR
            {
                void (C::*ptr)();
                unsigned long value[2];
            };
            CPTR cp;
            cp.ptr = &C::bfun;
            cout << hex << cp.value[0] << ' ' << cp.value[1] << dec << '\n';
        }

When this program is run, we see

        400b0c 0
        400b0c 4

(your address values (the first ones on the two lines) may differ). Note that the functions' addresses are the same, but since in the C world the B object lives beyond the A object, and the A object is 4 bytes large, we must add 4 to the value of the ``this`' pointer when calling the function from a C object. That's exactly what the shift value in the pointer's second field is telling the compiler.

- Table of Contents
- Previous Chapter
- Next Chapter