Condividi tramite


Puntatori a membri

Le dichiarazioni dei puntatori ai membri sono casi speciali di dichiarazioni del puntatore. Vengono dichiarati usando la sequenza seguente:

storage-class-specifiersopt cv-qualifiersopt type-specifier ms-modifieropt qualified-name ::* cv-qualifiersopt identifier pm-initializeropt ;

  1. Identificatore di dichiarazione:

    • Identificatore della classe di archiviazione facoltativo.

    • Identificatori e volatile facoltativiconst.

    • Il tipo di identificatore: il nome di un tipo. È il tipo del membro a cui puntare, non la classe .

  2. Dichiaratore:

    • Modificatore specifico di Microsoft facoltativo. Per altre informazioni, vedere Modificatori specifici di Microsoft.

    • Il nome completo della classe che contiene i membri a cui puntare.

    • Operatore ::.

    • Operatore *.

    • Identificatori e volatile facoltativiconst.

    • L'identificatore di denominazione del puntatore a membro.

  3. Inizializzatore facoltativo da puntatore a membro:

    • Operatore =.

    • Operatore &.

    • Nome completo della classe.

    • Operatore ::.

    • Nome di un membro non statico della classe del tipo appropriato.

Come sempre, più dichiaratori (e tutti gli inizializzatori associati) sono consentiti in una singola dichiarazione. Un puntatore al membro potrebbe non puntare a un membro statico della classe, a un membro di tipo riferimento o voida .

Un puntatore a un membro di una classe è diverso da un puntatore normale: dispone di entrambe le informazioni sul tipo del membro e della classe a cui appartiene il membro. Un puntatore normale identifica (con l'indirizzo) un singolo oggetto in memoria. Un puntatore a un membro di una classe identifica tale membro in qualsiasi istanza della classe. Nell'esempio seguente viene dichiarata una classe, Window, e alcuni puntatori ai dati dei membri.

// 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()
{
}

Nell'esempio precedente, pwCaption è un puntatore a qualsiasi membro della classe Window di tipo char*. Il tipo di pwCaption è char * Window::*. Il frammento di codice seguente dichiara i puntatori alle funzioni membro SetCaption e GetCaption.

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

I puntatori pfnwGC e pfnwSC puntano a GetCaption e SetCaption della classe Window, rispettivamente. Il codice copia informazioni nella didascalia della finestra direttamente tramite il puntatore a membro 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 differenza tra gli .* operatori e ->* (operatori puntatore a membro) è che l'operatore .* seleziona i membri forniti da un oggetto o un riferimento a un oggetto, mentre l'operatore ->* seleziona i membri tramite un puntatore. Per altre informazioni su questi operatori, vedere Espressioni con operatori puntatore a membro.

Il risultato degli operatori puntatore a membro è il tipo del membro. In questo caso, è char *.

Il frammento di codice seguente richiama le funzioni membro GetCaption e SetCaption tramite puntatori a membri:

// 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 );

Limitazioni sui puntatori ai membri

L'indirizzo di un membro statico non è un puntatore a un membro. Si tratta di un puntatore regolare all'istanza del membro statico. Esiste solo un'istanza di un membro statico per tutti gli oggetti di una determinata classe. Ciò significa che è possibile usare gli operatori ordinari address-of (&) e dereferenziazione (*).

Puntatori a membri e funzioni virtuali

Richiamare una funzione virtuale tramite una funzione puntatore a membro funziona come se la funzione fosse stata chiamata direttamente. La funzione corretta viene cercata nella tabella v e richiamata.

La chiave per le funzioni virtuali in esecuzione, come sempre, le richiama tramite un puntatore a una classe base. Per altre informazioni sulle funzioni virtuali, vedere Funzioni virtuali.

Nel codice seguente viene illustrato come richiamare una funzione virtuale con una funzione puntatore a membro:

// 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