pointers_to_members

멤버에 대한 포인터 선언은 포인터 선언의 특별한 경우입니다. 다음 시퀀스를 사용하여 선언됩니다.

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

  1. 선언 지정자:

    • 선택적 스토리지 클래스 지정자.

    • 선택 const 사항 및 volatile 지정자입니다.

    • 형식 지정자: 형식의 이름 클래스가 아니라 가리켰을 멤버의 형식입니다.

  2. 선언자:

    • 선택적 Microsoft 전용 한정자. 자세한 내용은 Microsoft 특정 한정자를 참조 하세요.

    • 가리킬 멤버가 포함된 클래스의 정규화된 이름입니다.

    • :: 연산자

    • * 연산자

    • 선택 const 사항 및 volatile 지정자입니다.

    • 멤버에 대한 포인터의 이름을 지정하는 식별자

  3. 선택적 포인터-멤버 이니셜라이저:

    • = 연산자

    • & 연산자

    • 클래스의 정규화된 이름

    • :: 연산자

    • 적절한 형식의 클래스에 대한 비정적 멤버의 이름입니다.

항상 그렇듯이 여러 선언자(및 모든 관련 이니셜라이저)가 단일 선언에서 허용됩니다. 멤버에 대한 포인터는 클래스의 정적 멤버, 참조 형식의 멤버 또는 void.

클래스의 멤버에 대한 포인터는 일반 포인터와 다릅니다. 멤버의 형식과 멤버가 속한 클래스에 대한 형식 정보가 모두 있습니다. 일반 포인터는 메모리에 있는 단일 개체만 식별합니다(해당 개체의 주소를 포함함). 클래스의 멤버에 대한 포인터는 클래스의 모든 인스턴스에서 해당 멤버를 식별합니다. 다음 예제에서는 Window 클래스와 멤버 데이터에 대한 몇 가지 포인터를 선언합니다.

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

앞의 예제 pwCaption 에서는 형식char*의 클래스 Window 멤버에 대한 포인터입니다. pwCaption의 형식은 char * Window::*입니다. 다음 코드에서는 SetCaptionGetCaption 멤버 함수에 대한 포인터를 선언합니다.

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

pfnwGCpfnwSC 포인터는 GetCaption 클래스의 SetCaptionWindow을 각각 가리킵니다. 이 코드에서는 멤버에 대한 포인터 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';

연산자와 ->* 연산자(포인터-멤버 연산자).*.* 차이점은 연산자가 개체 또는 개체 참조가 지정된 멤버를 선택하는 반면 ->* 연산자는 포인터를 통해 멤버를 선택한다는 것입니다. 이러한 연산자에 대한 자세한 내용은 포인터-멤버 연산자가 있는 식을 참조 하세요.

멤버에 대한 포인터 연산자의 결과는 멤버의 형식입니다. 이 예제의 경우 char *입니다.

다음 코드에서는 멤버에 대한 포인터를 사용하여 GetCaptionSetCaption 멤버 함수를 호출합니다.

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

멤버에 대한 포인터 제한

정적 멤버의 주소는 멤버에 대한 포인터가 아닙니다. 정적 멤버의 한 인스턴스에 대한 일반 포인터입니다. 지정된 클래스의 모든 개체에 대해 정적 멤버의 인스턴스가 하나만 존재합니다. 즉, 일반 주소(&) 및 역참조(*) 연산자를 사용할 수 있습니다.

멤버 및 가상 함수에 대한 포인터

포인터-멤버 함수를 통해 가상 함수를 호출하는 것은 함수가 직접 호출된 것처럼 작동합니다. 올바른 함수는 v 테이블에서 조회되고 호출됩니다.

가상 함수 작업은 항상 기본 클래스 포인터를 통해 호출합니다. (가상 함수 에 대한 자세한 내용은Virtual Functions.)

다음 코드에서는 멤버 포인터 함수를 통해 가상 함수를 호출하는 방법을 보여 줍니다.

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