Sdílet prostřednictvím


Ukazatelé na členy

Deklarace ukazatelů na členy jsou zvláštní případy deklarací ukazatelů. Deklarují se pomocí následující sekvence:

specifikátory třídy storage optcv-kvalifikátory opt type-specifierms-modifieroptqualified-name::*cv-kvalifikátoryoptidentifierpm-initializer opt;

  1. Specifikátor deklarace:

    • Volitelný specifikátor třídy úložiště.

    • Volitelné const a volatile specifikátory.

    • Specifikátor typu: název typu. Jedná se o typ člena, na který se má odkazovat, nikoli na třídu.

  2. Deklarátor:

    • Volitelný modifikátor specifický pro Microsoft. Další informace naleznete v tématu Modifikátory specifické pro Microsoft.

    • Kvalifikovaný název třídy obsahující členy, na které mají být odkazovat.

    • Operátor ::.

    • Operátor *.

    • Volitelné const a volatile specifikátory.

    • Identifikátor pojmenování ukazatele na člen.

  3. Volitelný inicializátor ukazatele na člen:

    • Operátor =.

    • Operátor &.

    • Kvalifikovaný název třídy.

    • Operátor ::.

    • Název nestatického člena třídy příslušného typu.

Stejně jako vždy je povoleno více deklarátorů (a všech přidružených inicializátorů) v jedné deklaraci. Ukazatel na člen nesmí odkazovat na statický člen třídy, člen referenčního typu nebo void.

Ukazatel na člen třídy se liší od normálního ukazatele: obsahuje informace o typu pro typ členu i pro třídu, do které člen patří. Normální ukazatel identifikuje (má adresu) pouze jeden objekt v paměti. Ukazatel na člen třídy identifikuje člena v libovolné instanci třídy. Následující příklad deklaruje třídu Windowa některé ukazatele na data členů.

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

V předchozím příkladu pwCaption je ukazatel na libovolný člen třídy Window , který je typu char*. Typ pwCaption je char * Window::*. Další fragment kódu deklaruje ukazatele na SetCaption členské funkce a GetCaption funkce.

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

Ukazatele pfnwGC a ukazují na GetCaption třídu a WindowSetCaptionpfnwSC v uvedeném pořadí. Kód zkopíruje informace do okna popis přímo pomocí ukazatele na členpwCaption:

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';

Rozdíl mezi operátory .* a ->* operátory (operátory ukazatele na člena) spočívá v tom, že .* operátor vybere členy vzhledem k objektu nebo objektu, zatímco ->* operátor vybere členy ukazatelem. Další informace o těchto operátorech naleznete v tématu Výrazy s operátory ukazatele na člena.

Výsledkem operátorů ukazatele na člen je typ členu. V tomto případě je to char *.

Následující fragment kódu vyvolá členské funkce GetCaption a SetCaption pomocí ukazatelů na členy:

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

Omezení ukazatelů členů

Adresa statického členu není ukazatel na člena. Je to běžný ukazatel na jednu instanci statického členu. Pro všechny objekty dané třídy existuje pouze jedna instance statického členu. To znamená, že můžete použít běžné operátory adres (&) a dereference (*).

Ukazatelé na členy a virtuální funkce

Vyvolání virtuální funkce prostřednictvím funkce ukazatele na člen funguje stejně, jako kdyby byla funkce volána přímo. Správná funkce se vyhledá v tabulce v a vyvolá se.

Klíč k fungování virtuálních funkcí je jako vždy volá prostřednictvím ukazatele na základní třídu. (Další informace o virtuálních funkcích najdete v tématu Virtuální funkce.)

Následující kód ukazuje, jak zavolat virtuální funkci pomocí funkce ukazatele na člen:

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