- Next chapter
- Previous chapter
- Table of contents

# Chapter 9: Classes having pointers to members

> We're always interested in getting feedback. E-mail us if you like this guide, if you think that important material is omitted, if you encounter errors in the code examples or in the documentation, if you find any typos, or generally just if you feel like e-mailing. Mail to Frank Brokken or use an e-mail form. Please state the concerned document version, found in the title.

Pointers in classes have been discussed in detail in chapter 5.1. As we have seen, when pointer data-members occur in classes, such classes deserve some special treatment.

By now it is well known how to treat pointer data members: constructors are used to initialize pointers, destructors are needed to free the memory pointed to by the pointer data members.

Furthermore, in classes having pointer data members copy constructors and overloaded assignment operators are normally needed as well.

However, in some situations we do not need a pointer to an object, but rather a pointer to members of an object. The realization of pointers to members of an object is the subject of this part of the C++ annotations.

## 9.1: Pointers to members: an example

Knowing how pointers to variables and objects are to be used does not intuitively lead to the concept of pointer to members. Even if the returntype and parametertypes of a memberfunction are taken into account, surprises are encountered. For example, consider the following class:

        class String
        {
            public:
                ...
                char const *get() const;
            private:
                ...
                char const *(*sp)() const;
        };

Within this class, it is not possible to define a `char const *(*sp)() const` pointing to the `get()` member function of the `String` class.

One of the reasons why this doesn't work is that the variable `sp` has a global scope, while the memberfunction `get()` is defined within the `String` class. The fact that the variable `sp` is part of the `String` class is of no relevance. According to `sp`'s definition, it points to a function outside of the class.

Consequently, in order to define a pointer to a member (either data or function, but usually a function) of a class, the scope of the pointer must be within the class' scope. Doing so, a pointer to a member of the class `String` can be defined as

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

So, due to the `String::` prefix, `sp` is defined to be active only in the context of the class `String`. In this context, it is defined as a pointer to a const function, not expecting arguments, and returning a pointer to const chars.

## 9.2: Initializing pointers to members

Pointers to members can be initialized to point to intended members. Such a pointer can be defined either inside or outside a member function.

Initializing or assigning an address to such a pointer does nothing but indicating which member the pointer will point to. However, member functions (except for the static member functions) can only be used when associated with an object of the member function's class. The same holds true for pointers to data members.

While it is allowed to initialize such a pointer outside of the class, it is not possible to access such a function without an associated object.

In the following example these characteristics are illustrated. First, a pointer is initialized to point to the function `String::get()`. In this case no `String` object is required.

Next, a `String` object is defined, and the string that is stored within the object is retrieved through the pointer, and not directly by the function `String::get()`. Note that the pointer is a variable existing outside of the class' context. This presents no problem, as the actual object to be used is identified by the statement in which object and pointervariable are combined. Consider the following piece of code:

        void fun()
        {
            char const
                *(String::*sp)() const;

            sp = String::get;   // assign the address
                                // of String's get()
                                // function

            String              // define a String object
                s("Hello world");

            cout << (s.*sp)()   // show the string
                 << endl;

            String
                *ps;            // pointer to a String object

            ps = &s;            // initialize ps to point at s

            cout << (ps->*sp)() // show the string again
                 << endl;
        }

Note in this example the statement `(s.*sp)()`. The `.*` construction indicates that `sp` is a pointer to a member function. Since the pointer variable `sp` points to the `String::get()` function, this function is now called, producing the string ```Hello world`''.

Furthermore, note the parentheses around `(s.*sp)`. These parentheses are required. If they were omitted, then the default interpretation (now parenthesized for further emphasis) would be `s.* (sp())`. This latter construction means

- Call function `sp()`, which should return a pointer to a member. E.g., `sp()` has the prototype
  `char const * (String::*)() sp();`
  So, `sp()` is a function returning a pointer to a memberfunction of the class `String`, while such a memberfunction must return a pointer to `const char`s.
- Apply this pointer with regard to object s.

Not an impossible or unlikely construction, but wrong as far as the current definition of `sp` is concerned.

When a pointer to a member function is associated with an object, the pointer to member selector operator `.*` is used. When a pointer to an object is used (instead of the object itself) the ``pointer to member through a pointer to a class object'' operator `->*` operator is required. The use of this operator is also illustrated in the above example.

## 9.3: Pointers to static members

Static members of a class exist without an object of their class. In other words, they can exist outside of any object of their class.

When these static members are public, they can be accessed in a `stand-alone' fashion.

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

        void fun()
        {
            cout << String::n_strings() << endl;
        }

Since pointers to members are always associated with an object, the use of a pointer to a memberfunction would normally produce an error. However, static members are actually global variables or functions, bound to their class.

Public static members can be treated as globally accessible functions and data. Private static members, on the other hand, can be accessed only from within the context of their class: they can only be accessed from inside the member functions of their class.

Since static members have no particular link with objects of their class, but look a lot like global functions, a pointer variable that is not part of the class of the member function must be used.

Consequently, a variable `int (*pfi)()` can be used to point to the static memberfunction `int String::n_strings()`, even though `int (*pfi)()` has nothing in common with the `class String`. This is illustrated in the next example:

        void fun()
        {
            int
                (*pfi)();

            pfi = String::n_strings;
                        // address of the  static memberfunction

            cout << pfi() << endl;
                        // print the value produced by
                        // String::n_strings()
        }

## 9.4: Using pointers to members for real

Let's assume that a database is created in which information about persons is stored. Name, street names, city names, house numbers, birthdays, etc. are collected in objects of the class `Person`, which are, in turn, stored in a class `Person_dbase`. Partial interfaces of these classes could be designed as follows:

        class Date;

        class Person()
        {
            public:
                ...
                char const *get_name() const;
                Date const &birthdate() const;
            private:
                ...
        };

        class Person_dbase
        {
            public:
                enum Listtype
                {
                    list_by_name,
                    list_by_birthday,
                };
                void list(Listtype type);
            private:
                Person
                    *pp;    // pointer to the info
                unsigned
                    n;      // number of persons stored.
        };

The organization of `Person` and `Person_dbase` is pictured in figure 10: Within a `Person_dbase` object the `Person` objects are stored. They can be reached via the pointer variable `Person *pp`.

figure 10: Person_dbase objects: Persons reached via Person *pp

We would like to develop the function `Person_dbase::list()` in such a way that it lists the contents of the database sorted according to a selected field of a `Person` object.

So, when `list()` is called to list the database sorted by names, the database of `Person` objects is first sorted by names, and is then listed.

Alternatively, when `list()` is called to list the database sorted by birthdates, the database of `Person` objects is first sorted by birthdates, and is then listed.

In this situation, the function `qsort()` is most likely called to do the actual sorting of the `Person` objects ( In the current implementation `pp` points to an array of `Person` objects. In this implementation, the function `qsort()` will have to copy the actual `Person` objects again and again, which may be rather inefficient when the `Person` objects become large. Under an alternative implementation, in which the `Person` objects are reached through pointers, the efficiency of the `qsort()` function will be improved. In that case, the datamember `pp` will have to be declared as `Person **pp`.). This function requires a pointer to a compare function, comparing two elements of the array to be sorted. The prototype of this compare function is

`int (*)(void const *, void const *)`
However, when used with `Person` objects, the prototype of the `compare()` function should be
`int (*)(Person const *, Person const *)`
Somewhere a typecast will be required: either when calling `qsort()`, or within the `compare()` functions themselves. We will use the typecast when calling `qsort()`, using the following typedef to reduce the verbosity of the typecasts (a pointer to an integer function requiring two void pointers):
`typedef int (*pif2vp)(void const *, void const *)`

Next, the function `list()` could be developed according to the following setup:

        void Person_dbase::list(Listtype type)
        {
            switch (type)
            {
                case list_by_name:
                    qsort(pp, n, sizeof(Person), (pif2vp)cmpname);
                break;

                case list_by_birthday:
                    qsort(pp, n, sizeof(Person), (pif2vp)cmpdate);
                break;
            }
            // list the sorted Person-database
        }

There are several reasons why this setup is not particularly desirable:

- Although the example only shows two list-alternatives (sort by name and sort by birthday), a real-life implementation will have many more ways to list the information. This will soon result in a very long function `list()` which will be hard to maintain and will look inaccessible due to its length.
- Every time a new way to list the data in the database, the function `list()` will have to be expanded, by offering an extra `case` label for every new way to list the data.
- Much of the code in the function `list()` will be repeated within the function, showing only some small differences.

Much of the complexity of `list()` function could be reduced by defining pointers to the compare-functions, storing these pointers in an array. Since this array will be common to all `Person_dbase` objects, it should be defined as a static array, containing the pointers to the compare-functions.

Before actually constructing this array, note that this approach requires the definition of as many compare functions as there are elements in the `Listtype` enum. So, to list the information sorted by name a function `cmpname()` is used, comparing the names stored in two `Person` objects, while a function `cmpcity()`, is used to compare cities. Somehow this seems to be redundant as well: we would like to use one function to compare strings, whatever their meanings. Comparable considerations hold true for other fields of information.

The compare functions, however, receive pointers to `Person` objects. Therefore, the data-members of the `Person` objects to which these pointers point can be accessed using the access-memberfunctions of the `Person` class. So, the compare functions can access these data-members as well, using the pointers to the `Person` objects.

Now note that the access memberfunctions that are used within a particular compare function can be hard-coded, by plainly mentioning the accessors to be used, and they can be selected indirectly, by using pointers to the accessors to be used.

This latter solution allows us to merge compare functions that use the same implementations, but use different accessors: By setting a pointer to the appropriate accessor function just before the compare function is called, one single compare function can be used to compare many different kinds of data stored inside `Person` objects.

The compare functions themselves are used within the context of the `Person_dbase` class, where they are passed to the `qsort()` function. The `qsort()` function, however, is a global function. Consequently, the compare functions can't be ordinary member functions of the class `Person_dbase`, but they must be static members of that class, so they can be passed to the `qsort()` function.

Summarizing what we've got so far, we see that the problem has been broken down as follows:

- The `switch` construction in the `list()` function should be replaced by a call to a function using a pointer to a function.
- The actual function to be used is determined by the value of the selector, which is given to `list()` when it's called.
- The `compare()` functions may be further abstracted by combining those comparing the same types.
- When `compare()` functions are combined, the access memberfunction of the `Person` objects to be used will also be found via an array containing pointers to the access member functions of `Person` objects.
- The `compare()` functions are part of the `Person_dbase` class, but it must also be possible to give their addresses as arguments to `qsort()`. Hence, these functions must be defined as static functions of the class `Person_dbase`.

From this analysis the essential characteristics of the proposed implementation emerge.

For every type of listing, as produced by the function `list()`, the following is required:

- The access member function of the `Person` class to be used.
- The `compare()` function to be used. The `compare()` functions will be static functions of the class `Person_dbase`, so that they can be passed over to `qsort()`

This information does not depend on a particular `Person_dbase` object, but is common to all of these objects. Hence it will be stored compile-time in a `static Person_dbase` kind of array.

How will the `compare()` functions know which element of this array to use? The requested index is passed to the `list()` member function as a `Listtype` value. The `list()` function can then save this information in a `static Person_dbase::Listtype` variable for the `compare()` functions to use.

We've analyzed enough. Let's build it this way.

### 9.4.1: Pointers to members: an implementation

- First, the necessary class interfaces are defined. The existence of a class `Date` is assumed, containing overloaded operators like `<` and `>` to compare dates. To start with, we present the interface of the class `Person`, omitting all the standard stuff like overloaded assignment operator, (copy) constructors, etc.:

          #include <stdlib.h>     // for qsort()

          class Date;

          class Person()
          {
              public:
                  unsigned length() const;
                  unsigned weight() const;
                  char const *name() const;
                  char const *city() const;
                  Date const &birthdate() const;

              private:
                  // all necessary data members
          };

- Next, the class `Person_dbase`. Within this class a `struct CmpPerson` is defined, containing two fields:

  - A pointer to a union of compare functions.

    As the compare functions are static functions of the class `Person_dbase`, pointers to these functions are indiscernible from pointers to functions at the global (`::`) level. The compare functions return `int`s (for `qsort()`), and expect two pointers to `Person const` objects. The field `persons` expects the two pointers to `Person const` objects. The field `voids` is the alternate interpretation, to be used with `qsort()`, instead of the typecast `(pif2vp)`.

  - A field `pf` (pointer to access function) of the nested `union Person_accessor`.

    The types of as many different access functions of the `Person` class as are used in the class are declared in this union.

    Access functions returning `int`s, `char const *`s and `Date &`s will be needed. Consequently, the `Person_accessor` union contains these (three) types.

  From this `CmpPerson` struct a static array `cmpPerson[]` is constructed. It is a `static Person_dbase` array, making it possible for the compare functions to inspect its elements ( The number of elements of the `cmpPerson[]` array is not specified in the interface: that number is determined compile-time by the compiler, when the static variable `cmpPerson[]` is initialized.).

  Also note the `static Listtype selector`. This variable will be used later in the compare functions to find the actual `Person` access function to be used. Here, then, is the interface of the class `Person_dbase`:

          class Person_dbase
          {
              public:
                  enum Listtype
                  {
                      list_by_length,
                      list_by_weight,
                      list_by_name,
                      list_by_city,
                      list_by_birthday,
                  };

                  // ... constructors etc.

                  void list(Listtype type);
                              // list the information
              private:
                  struct CmpPerson
                  {
                      union Compare_function
                      {
                          int (*persons)// comparing two Persons
                              (Person const *p1, Person const *p2);
                          int (*voids)// for qsort()
                              (void const *p1, void const *p2);
                      }
                          cmp;

                      union Person_accessor
                      {
                          char const
                              *(Person::*cp)() const;
                          int
                              (Person::*i)() const;
                          Date const
                              &(Person::*d)() const;
                      }
                          pf;     // to Person's access functions
                  };

                  static CmpPerson
                      cmpPerson[];
                  static Listtype
                      selector;

                  static int cmpstr(Person const *p1,
                                    Person const *p2);

                  static int cmpint(Person const *p1,
                                    Person const *p2);

                  static int cmpdate(Person const *p1,
                                    Person const *p2);

                  Person
                      *pp;    // pointer to the info
                  unsigned
                      n;      // number of persons stored.
          };

  Next, we define each of the members of the `Person_dbase` class (as far as necessary).

- The `list()` function now only has to do three things:
  - The `Listtype` parameter is copied to `selector`,
  - The function `qsort()` is called. Note the use of the `cmpPerson` array to determine which compare function to use.
  - The information of the `Person`objects is displayed. This part is left for the reader to implement.

          void Person_dbase::list(Listtype type)
          {
              selector = type;
              qsort(pp, n, sizeof(Person), cmpPerson[type].cmp.voids);
              // list the sorted Person-database (to be implemented)
          }

- The array `cmpPerson[]` is a static array of `CmpPerson` elements. In this example there are five different ways to sort the data. Consequently, there are five elements in the array `cmpPerson[]`. All these elements can be defined and initialized by the compiler. No run-time execution time is needed for this.

  However, note the form of the declaration: the array is defined in the scope of the `Person_dbase` class. Its elements are `CmpPerson`s, also defined in the scope of the `Person_dbase` class. Hence the double mentioning of `Person_dbase`.

          Person_dbase::CmpPerson
              Person_dbase::cmpPerson[] =
              {
                  {       // compare- and access
                          // function to compare length
                      cmpint,
                      Person::length,
                  },

                  {       // same for weight
                      cmpint,
                      Person::weight,
                  },

                  {       // same for name
                      cmpstr,
                      Person::name,
                  },

                  {       // same for city
                      cmpstr,
                      Person::city,
                  },

                  {       // same for Date
                      cmpdate,
                      Person::birthdate,
                  },
              };

- Now only the compare functions remain to be implemented. Although five accessors can be used, only three compare functions are needed.

  The compare functions, being static functions, have access to the `cmpPerson[]` array and to the `Listtype selector` variable. This information is used by the compare functions to call the relevant access member function of the two `Person` objects, pointed to by the parameters of the compare functions.

  For this, the `pointer to member` operator `->*` is used. The element `cmpPerson[selector]` contains the function pointers to the functions to be used: they are the fields `pf`, variant `cp, i` or `d`. These fields return a pointer to a particular access function of a `Person` object.

  Through these pointers the functions can be associated to a particular `Person` object using the pointer to member operator. This results in expressions like:

  `p1->*cmpPerson[selector].pf.cp`

  By this time we have the name (i.e., address) of an access function for a particular `Person` object. To call this function, parentheses are needed, one set of parentheses to protect this expression from desintegrating due to the high priority of the second set of parentheses, which are needed for the actual call of the function. Hence, we get:

  `(p1->*cmpPerson[selector].pf.cp)()`

  Finally, here are the three compare functions:

          int Person_dbase::cmpstr(Person const *p1, Person const *p2)
          {
              return
              (
                  strcmp
                  (
                      (p1->*cmpPerson[selector].pf.cp)(),
                      (p2->*cmpPerson[selector].pf.cp)()
                  )
              );
          }

          int Person_dbase::cmpint(Person const *p1, Person const *p2)
          {
              return
              (
                  (p1->*cmpPerson[selector].pf.i)()
                  -
                  (p2->*cmpPerson[selector].pf.i)()
              );
          }

          int Person_dbase::cmpdate(Person const *p1, Person const *p2)
          {
              return
              (
                  (p1->*cmpPerson[selector].pf.d)()
                  <
                  (p2->*cmpPerson[selector].pf.d)() ?
                      -1
                  :
                      (p1->*cmpPerson[selector].pf.d)()
                      >
                      (p2->*cmpPerson[selector].pf.d)()
              );
          }

- Next chapter
- Previous chapter
- Table of contents