Pointers to Members

Declarations of pointers to members are special cases of pointer declarations.

Syntax

decl-specifiers class-name:: *cv-qualifier-listopt dname;

A pointer to a member of a class differs from a normal pointer because it has type information for not only the type of the member, but also for the class to which the member belongs. The following example declares a class, Window, then some pointers to member data.

class Window

{

public:

Window(); // Default constructor.

Window( int x1, int y1, // Constructor specifying

int x2, int y2 ); // window size.

BOOL SetCaption( const char *szTitle ); // Set window caption.

const char *GetCaption(); // Get window caption.

char *szWinCaption; // Window caption.

};

// Declare a pointer to the data member szWinCaption.

char * Window::* pwCaption = &Window::szWinCaption;

In the preceding example, pwCaption is a pointer of type char * that is a member of class Window. The next code fragment declares pointers to the SetCaption and GetCaption member functions.

const char * (Window::*pfnwGC)() = &Window::GetCaption;

BOOL (Window::*pfnwSC)( const char * ) = &Window::SetCaption;

The pointers pfnwGC and pfnwSC point to GetCaption and SetCaption of the Window class, respectively. To copy information to the window caption directly using the pointer to member pwCaption, use code such as this:

Window wMainWindow;

Window *pwChildWindow = new Window;

char *szUntitled = "Untitled - ";

int cUntitledLen = strlen( szUntitled );

strcpy( wMainWindow.*pwCaption, szUntitled );

(wMainWindow.*pwCaption)[cUntitledLen - 1] = '1';

strcpy( pwChildWindow->*pwCaption, szUntitled );

(pwChildWindow->*pwCaption)[szUntitledLen - 1] = '2';

The difference between the .* and –>* operators (the pointer-to-member operators) is that the .* operator is used to select members of an object, while the –>* operator is used to select members through a pointer. (For more about these operators, see “Expressions with Pointer-to-Member Operators” in Chapter 4, on topic .)

Note that the result of the pointer-to-member operators is the type of the member—in this case, char *.

The following code fragment invokes the member functions GetCaption and SetCaption using pointers to members:

// Allocate a buffer.

char szCaptionBase[100];

// Copy the main window caption into the buffer

// and append " [View 1]".

strcpy( szCaptionBase, (wMainWindow.*pfnwGC)() );

strcat( szCaptionBase, " [View 1]" );

// Set the child window's caption.

(pwChildWindow->*pfnwSC)( szCaptionBase );

Restrictions on Pointers to Members

It is illegal to declare pointers to static class members. Because only one instance of a static member exists for all objects of a given class, the ordinary address-of (&) and dereference (*) operators can be used.

Pointers to Members and Virtual Functions

Invoking a virtual function through a pointer-to-member function works exactly as if the function had been called directly: the correct function is looked up in the v-table and invoked. The following code shows how this is done:

class Base

{

public:

virtual void Print();

};

void (Base ::* bfnPrint)() = &Base :: Print;

void Base :: Print()

{

cout << "Print function for class 'Base'\n";

}

class Derived : public Base

{

public:

void Print(); // Print is still a virtual function.

};

void Derived :: Print()

{

cout << "Print function for class 'Derived'\n";

}

main()

{

Base *bPtr;

Base bObject;

Derived dObject;

bPtr = &bObject; // Set pointer to address of bObject.

(bPtr->*bfnPrint)();

bPtr = &dObject; // Set pointer to address of dObject.

(bPtr->*bfnPrint)();

return 0;

}

The output from this program is:

Print function for class 'Base'

Print function for class 'Derived'

The key to virtual functions working, as always, is invoking them through a pointer to a base class. (For more information about virtual functions, see “Virtual Functions” in Chapter 9, on topic .)