Punteros a miembros

Las declaraciones de punteros a miembros son casos especiales de declaraciones de puntero. Se declaran mediante la secuencia siguiente:

storage-class-specifiersoptcv-qualifiersopttype-specifierms-modifieroptqualified-name::*cv-qualifiersoptidentifierpm-initializeropt;

  1. El especificador de declaración:

    • Un especificador de clase de almacenamiento opcional.

    • Especificadores const y volatile opcionales.

    • El especificador de tipo: el nombre de un tipo. Es el tipo del miembro al que se apunta, no la clase.

  2. El declarador:

    • Modificador opcional concreto de Microsoft. Para obtener más información, consulte Modificadores específicos de Microsoft.

    • El nombre completo de la clase que contiene los miembros a los que se señala.

    • El operador ::.

    • El operador *.

    • Especificadores const y volatile opcionales.

    • El identificador que denomina el puntero a miembro.

  3. Un inicializador opcional de puntero a miembro:

    • El operador =.

    • El operador &.

    • Nombre completo de la clase.

    • El operador ::.

    • El nombre de un miembro no estático de la clase del tipo adecuado.

Como siempre, se permiten varios declaradores (y cualesquiera inicializadores asociados) en una sola declaración. Un puntero a un miembro podría no apuntar a un miembro estático de la clase, un miembro de tipo de referencia o void.

Un puntero a un miembro de una clase se diferencia de un puntero normal en que tiene información del tipo de miembro y de la clase a la que pertenece el miembro. Un puntero normal identifica (tiene la dirección de) un solo objeto en memoria. Un puntero a un miembro de una clase identifica ese miembro en cualquier instancia de la clase. En el ejemplo siguiente se declara una clase, Window, y algunos punteros a los datos de miembros.

// pointers_to_members1.cpp
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;
int main()
{
}

En el ejemplo anterior, pwCaption es un puntero a cualquier miembro de la clase Window que tenga el tipo char*. El tipo de pwCaption es char * Window::*. El siguiente fragmento de código declara punteros a las funciones miembro SetCaption y GetCaption.

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

Los punteros pfnwGC y pfnwSC señalan, respectivamente, a GetCaption y a SetCaption de la clase Window. El código copia la información en la leyenda de la ventana directamente mediante el puntero al miembro pwCaption:

Window  wMainWindow;
Window *pwChildWindow = new Window;
char   *szUntitled    = "Untitled -  ";
int     cUntitledLen  = strlen( szUntitled );

strcpy_s( wMainWindow.*pwCaption, cUntitledLen, szUntitled );
(wMainWindow.*pwCaption)[cUntitledLen - 1] = '1';     // same as
// wMainWindow.SzWinCaption [cUntitledLen - 1] = '1';
strcpy_s( pwChildWindow->*pwCaption, cUntitledLen, szUntitled );
(pwChildWindow->*pwCaption)[cUntitledLen - 1] = '2'; // same as
// pwChildWindow->szWinCaption[cUntitledLen - 1] = '2';

La diferencia entre los operadores .* y ->* (los operadores de puntero a miembro) consiste en que el operador .* selecciona los miembros con un objeto o una referencia de objeto especificados, mientras que el operador ->* selecciona los miembros mediante un puntero. Para obtener más información sobre estos operadores, consulte Expresiones con operadores de puntero a miembro.

El resultado de los operadores de puntero a miembro es el tipo de miembro. En este caso, es char *.

El fragmento de código siguiente invoca las funciones miembro GetCaption y SetCaption mediante punteros a miembros:

// Allocate a buffer.
enum {
    sizeOfBuffer = 100
};
char szCaptionBase[sizeOfBuffer];

// Copy the main window caption into the buffer
//  and append " [View 1]".
strcpy_s( szCaptionBase, sizeOfBuffer, (wMainWindow.*pfnwGC)() );
strcat_s( szCaptionBase, sizeOfBuffer, " [View 1]" );
// Set the child window's caption.
(pwChildWindow->*pfnwSC)( szCaptionBase );

Restricciones de los punteros a miembros

La dirección de un miembro estático no es un puntero a un miembro. Es un puntero normal a la única instancia del miembro estático. Solo existe una instancia de un miembro estático para todos los objetos de una clase determinada. Esto significa que puede usar los operadores de dirección normal de (&) y desreferencia (*).

Punteros a funciones virtuales y de miembro

La invocación de una función virtual mediante una función de puntero a miembro funciona como si se hubiera llamado directamente a la función. La función correcta se busca en v-table y se invoca.

La clave para trabajar con funciones virtuales es, como siempre, invocarlas a través de un puntero a una clase base. (Para obtener más información sobre las funciones virtuales, consulte Funciones virtuales).

El código siguiente muestra cómo invocar una función virtual a través de una función de puntero a miembro:

// virtual_functions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

class Base
{
public:
    virtual void Print();
};
void (Base::* bfnPrint)() = &Base::Print;
void Base::Print()
{
    cout << "Print function for class Base" << endl;
}

class Derived : public Base
{
public:
    void Print();  // Print is still a virtual function.
};

void Derived::Print()
{
    cout << "Print function for class Derived" << endl;
}

int 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)();
}

// Output:
// Print function for class Base
// Print function for class Derived