Wskaźniki do elementów członkowskich

Deklaracje wskaźników do składowych są specjalnymi przypadkami deklaracji wskaźnika. Są one deklarowane przy użyciu następującej sekwencji:

specyfikatory klasy magazynu optcv-kwalifikatoryopt-specyfikatortypu ms-modifieroptkwalifikowanej nazwy::*cv-kwalifikatoryoptidentyfikatorpm-initializeropt opt;

  1. Specyfikator deklaracji:

    • Opcjonalny specyfikator klasy magazynu.

    • Opcjonalne const i volatile specyfikatory.

    • Specyfikator typu: nazwa typu. Jest to typ elementu członkowskiego do wskazywania, a nie klasy.

  2. Deklarator:

    • Opcjonalny modyfikator specyficzny dla firmy Microsoft. Aby uzyskać więcej informacji, zobacz Modyfikatory specyficzne dla firmy Microsoft.

    • Kwalifikowana nazwa klasy zawierającej elementy członkowskie do wskazywania.

    • Operator ::.

    • Operator *.

    • Opcjonalne const i volatile specyfikatory.

    • Identyfikator nazewnictwa wskaźnika do elementu członkowskiego.

  3. Opcjonalny inicjator wskaźnika do elementu członkowskiego:

    • Operator =.

    • Operator &.

    • Kwalifikowana nazwa klasy.

    • Operator ::.

    • Nazwa niestacjonanej składowej klasy odpowiedniego typu.

Tak jak zawsze, wiele deklaratorów (i wszystkich skojarzonych inicjatorów) jest dozwolonych w jednej deklaracji. Wskaźnik do składowej może nie wskazywać statycznej składowej klasy, składowej typu odwołania lub void.

Wskaźnik do składowej klasy różni się od normalnego wskaźnika: ma zarówno informacje o typie elementu członkowskiego, jak i dla klasy, do której należy składowa. Normalny wskaźnik identyfikuje (ma adres) tylko jeden obiekt w pamięci. Wskaźnik do składowej klasy identyfikuje ten element członkowski w dowolnym wystąpieniu klasy. Poniższy przykład deklaruje klasę , Windowi niektóre wskaźniki do danych składowych.

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

W poprzednim przykładzie pwCaption jest wskaźnikiem do dowolnej składowej klasy Window typu char*. Typ to pwCaptionchar * Window::*. Następny fragment kodu deklaruje wskaźniki do funkcji składowych SetCaption i GetCaption .

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

pfnwGC Wskaźniki i pfnwSC wskazują GetCaption odpowiednio i SetCaption klasęWindow. Kod kopiuje informacje do okna podpis bezpośrednio przy użyciu wskaźnika do elementu członkowskiego 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';

Różnica między operatorami .* i ->* (operatorami wskaźnika do składowych) polega na tym, że .* operator wybiera elementy członkowskie, biorąc pod uwagę odwołanie do obiektu lub obiektu, podczas gdy ->* operator wybiera elementy członkowskie za pomocą wskaźnika. Aby uzyskać więcej informacji na temat tych operatorów, zobacz Wyrażenia z operatorami wskaźników do składowych.

Wynikiem operatorów wskaźnika do elementu członkowskiego jest typ elementu członkowskiego. W tym przypadku jest to char *.

Poniższy fragment kodu wywołuje funkcje GetCaption składowe i SetCaption używa wskaźników do elementów członkowskich:

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

Ograniczenia dotyczące wskaźników do elementów członkowskich

Adres statycznego elementu członkowskiego nie jest wskaźnikiem do elementu członkowskiego. Jest to zwykły wskaźnik do jednego wystąpienia statycznego elementu członkowskiego. Istnieje tylko jedno wystąpienie statycznego elementu członkowskiego dla wszystkich obiektów danej klasy. Oznacza to, że można użyć zwykłych operatorów adres-of (&) i dereference (*).

Wskaźniki do elementów członkowskich i funkcji wirtualnych

Wywoływanie funkcji wirtualnej za pośrednictwem funkcji wskaźnik-składowa działa tak, jakby funkcja została wywołana bezpośrednio. Poprawna funkcja jest sprawdzana w tabeli wirtualnej i wywoływana.

Kluczem do funkcji wirtualnych działa, jak zawsze, jest wywoływanie ich za pośrednictwem wskaźnika do klasy bazowej. (Aby uzyskać więcej informacji na temat funkcji wirtualnych, zobacz Funkcje wirtualne.

Poniższy kod pokazuje, jak wywołać funkcję wirtualną za pomocą funkcji wskaźnika do składowej:

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