Pointeurs vers membres

Les déclarations de pointeurs vers des membres sont des cas spéciaux de déclarations de pointeur. Ils sont déclarés à l’aide de la séquence suivante :

storage-class-specifiersoptcv-qualifiersopttype-specifierms-modificateuroptqualified-name::*cv-qualifiersoptidentifierpm-initializer opt;

  1. Spécificateur de déclaration :

    • Spécificateur de classe de stockage facultatif.

    • Spécificateurs et volatile facultatifsconst.

    • Spécificateur de type : nom d'un type. Il s’agit du type du membre auquel faire référence, et non de la classe.

  2. Déclarateur :

    • Modificateur spécifique à Microsoft facultatif. Pour plus d’informations, consultez Modificateurs spécifiques à Microsoft.

    • Nom qualifié de la classe contenant les membres vers lesquels pointer.

    • opérateur ::,

    • opérateur *,

    • Spécificateurs et volatile facultatifsconst.

    • Identificateur nommant le pointeur vers le membre.

  3. Initialiseur de pointeur à membre facultatif :

    • opérateur =,

    • opérateur &,

    • Nom qualifié de la classe.

    • opérateur ::,

    • Nom d’un membre non statique de la classe du type approprié.

Comme toujours, les déclarateurs multiples (et tout initialiseur associé) sont autorisés dans une même déclaration. Un pointeur vers un membre peut ne pas pointer vers un membre statique de la classe, un membre de type référence ou void.

Un pointeur vers un membre d’une classe diffère d’un pointeur normal : il contient à la fois des informations de type pour le type du membre et pour la classe à laquelle appartient le membre. Un pointeur normal identifie (a l'adresse de) un seul objet en mémoire. Un pointeur vers un membre d'une classe identifie ce membre dans toute instance de la classe. L'exemple suivant déclare une classe, Window, et certains pointeurs vers des données membres.

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

Dans l’exemple précédent, pwCaption est un pointeur vers n’importe quel membre de classe Window de type char*. Le type de pwCaption est char * Window::*. Le fragment de code suivant déclare des pointeurs vers les fonctions membres SetCaption et GetCaption.

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

Les pointeurs pfnwGC et pfnwSC pointent respectivement vers GetCaption et SetCaption de la classe Window. Le code copie directement des informations vers le titre de la fenêtre à l'aide du pointeur vers le membre 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 différence entre les opérateurs et les .*->* opérateurs (opérateurs pointeur à membre) est que l’opérateur .* sélectionne les membres en fonction d’un objet ou d’une référence d’objet, tandis que l’opérateur ->* sélectionne des membres via un pointeur. Pour plus d’informations sur ces opérateurs, consultez Expressions avec des opérateurs pointeur vers membre.

Le résultat des opérateurs pointeur à membre est le type du membre. Dans ce cas, il s’agit de char *.

Le fragment de code suivant appelle les fonctions membres GetCaption et SetCaption à l'aide de pointeurs vers des membres :

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

Restrictions sur les pointeurs vers des membres

L’adresse d’un membre statique n’est pas un pointeur vers un membre. Il s’agit d’un pointeur normal vers l’instance du membre statique. Une seule instance d’un membre statique existe pour tous les objets d’une classe donnée. Cela signifie que vous pouvez utiliser les opérateurs d’adresse ordinaire (&) et de déréférencement (*).

Pointeurs vers des membres et des fonctions virtuelles

L’appel d’une fonction virtuelle par le biais d’une fonction pointeur à membre fonctionne comme si la fonction avait été appelée directement. La fonction correcte est recherchée dans la table v et appelée.

La clé du bon fonctionnement des fonctions virtuelles est, comme toujours, de les appeler via un pointeur vers une classe de base. (Pour plus d’informations sur les fonctions virtuelles, consultez Fonctions virtuelles.)

Le code suivant montre comment appeler une fonction virtuelle via un pointeur de fonction membre :

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