メンバーへのポインター

メンバーへのポインターの宣言は、ポインター宣言の特殊なケースです。 これらは次のシーケンスで宣言します。

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

  1. 宣言指定子:

    • ストレージ クラスの指定子 (省略可能)。

    • constvolatile 指定子 (省略可能)。

    • 型指定子: 型の名前。 これは指されるメンバーのクラスではなく、型です。

  2. 宣言子:

    • オプションの Microsoft 固有の修飾子。 詳細については、「Microsoft 固有の修飾子」を参照してください。

    • 指されるメンバーが含まれるクラスの修飾名。

    • :: 演算子。

    • * 演算子。

    • constvolatile 指定子 (省略可能)。

    • メンバーへのポインターを指定する識別子。

  3. オプションのメンバーへのポインター初期化子:

    • = 演算子。

    • & 演算子。

    • クラスの修飾名。

    • :: 演算子。

    • 適切な型のクラスの非静的メンバーの名前。

当然ながら、1 つの宣言で複数の宣言子 (および関連する初期化子) を使用できます。 メンバーへのポインターは、クラスの静的メンバー、参照型のメンバー、または void を指すことはできません。

クラスのメンバーへのポインターは、メンバーの種類の情報とメンバーが属するクラスの型情報の両方を持つ点で、通常のポインターとは異なります。 通常のポインターは、メモリ内の 1 つのオブジェクトだけを識別します (1 つのオブジェクトのアドレスだけを持ちます)。 クラスのメンバーへのポインターは、クラスのインスタンスのメンバーを識別します。 次の例では、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::* です。 次のコードでは、メンバー関数 SetCaption および GetCaption へのポインターを宣言します。

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

ポインター pfnwGC および pfnwSC はそれぞれ、GetCaption クラスの SetCaption および Window を指します。 次のコードは、メンバー 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 * です。

次のコードでは、メンバーへのポインターを使用して、メンバー関数 GetCaption および SetCaption を呼び出します。

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

メンバーへのポインターに関する制約

静的メンバーのアドレスは、メンバーへのポインターではありません。 それは静的メンバーの 1 つのインスタンスへの通常のポインターです。 静的メンバーのインスタンスが存在するのは、特定のクラスのすべてのオブジェクトに対して 1 つのみです。 つまり、通常のアドレス演算子 (> 演算子と逆参照演算子*) を使用できます。

メンバーと仮想関数へのポインター

メンバーへのポインター関数を介して仮想関数を呼び出すと、その関数が直接呼び出された場合と同様に動作します。 正しい関数が v テーブルで検索され、呼び出されます。

この場合も、仮想関数が正しく機能するうえで重要なことは、基底クラスへのポインターを介して仮想関数を呼び出すことです。 (仮想関数の詳細については、「仮想関数」を参照してください)。

次のコードは、メンバー関数へのポインターを介して仮想関数を呼び出す方法を示しています。

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