C++プログラミングにおけるネストされたクラスの宣言とその関数の使用を詳しく理解する

4764 ワード

1つのクラスの範囲内で別のクラスを宣言できます.このようなクラスを「ネストクラス」と呼ぶ.ネストされたクラスは、閉じたクラスの範囲内とみなされ、その範囲内で使用できます.ネストされたクラスの即時閉鎖範囲外の範囲からクラスを参照するには、完全限定名を使用する必要があります.次の例では、ネストされたクラスを宣言する方法を示します.

// nested_class_declarations.cpp
class BufferedIO
{
public:
  enum IOError { None, Access, General };

  // Declare nested class BufferedInput.
  class BufferedInput
  {
  public:
   int read();
   int good()
   {
     return _inputerror == None;
   }
  private:
    IOError _inputerror;
  };

  // Declare nested class BufferedOutput.
  class BufferedOutput
  {
   // Member list
  };
};

int main()
{
}


BufferedIO::BufferedInputでBufferedIO::BufferedOutputとBufferedIOを宣言します.これらのクラス名は、クラスBufferedIOの範囲外では表示されません.ただし、BufferedIOタイプのオブジェクトには、BufferedInputまたはBufferedOutputタイプのオブジェクトは含まれません.ネストされたクラスは、閉じたクラスから名前、タイプ名、静的メンバーの名前、列挙数のみを直接使用できます.他のクラスメンバーの名前を使用するには、ポインタ、参照、またはオブジェクト名を使用する必要があります.前述のBufferedIOの例では、列挙IOErrorは、関数goodに示すように、ネストされたクラスのメンバー関数、BufferedIO::BufferedInputまたはBufferedIO::BufferedOutputから直接アクセスすることができる.ネストされたクラスは、クラス範囲内でのみタイプを宣言することに注意してください.ネストされたクラスの包含オブジェクトは作成されません.前の例では、2つのネストされたクラスが宣言されていますが、これらのクラスタイプのオブジェクトは宣言されていません.タイプ名を順方向宣言とともに宣言すると、ネストされたクラス宣言の範囲の可視性に異常が発生します.この場合、宣言されたクラス名は、閉じたクラスの外部に表示され、その範囲は最小の閉じた非クラス範囲として定義されます.例:

// nested_class_declarations_2.cpp
class C
{
public:
  typedef class U u_t; // class U visible outside class C scope
  typedef class V {} v_t; // class V not visible outside class C
};

int main()
{
  // okay, forward declaration used above so file scope is used
  U* pu;

  // error, type name only exists in class C scope
  u_t* pu2; // C2065

  // error, class defined above so class C scope
  V* pv; // C2065

  // okay, fully qualified name
  C::V* pv2;
}


ネストされたクラスのアクセス権は、あるクラスを別のクラスに埋め込むと、埋め込まれたクラスのメンバー関数に特別なアクセス権は与えられません.同様に、閉じたクラスのメンバー関数には、ネストされたクラスのメンバーへの特別なアクセス権はありません.ネストされたクラスのメンバー関数ネストされたクラスで宣言されたメンバー関数は、ファイル範囲で定義できます.前の例は、次のように記述されています.

// member_functions_in_nested_classes.cpp
class BufferedIO
{
public:
  enum IOError { None, Access, General };
  class BufferedInput
  {
  public:
    int read(); // Declare but do not define member
    int good(); // functions read and good.
  private:
    IOError _inputerror;
  };

  class BufferedOutput
  {
    // Member list.
  };
};
// Define member functions read and good in
// file scope.
int BufferedIO::BufferedInput::read()
{
  return(1);
}

int BufferedIO::BufferedInput::good()
{
  return _inputerror == None;
}
int main()
{
}


前の例では、qualified-type-name構文を使用して関数名を宣言します.宣言:

BufferedIO::BufferedInput::read()

「BufferedInputクラスの範囲内にあるreadクラスのメンバーであるBufferedIO関数」を表します.この宣言はqualified-type-name構文を使用するため、次の形式の構造が可能です.

typedef BufferedIO::BufferedInput BIO_INPUT;

int BIO_INPUT::read()


上記の宣言は、前の宣言と同等ですが、クラス名の代わりにtypedef名を使用します.ネストされたクラスの友元関数ネストされたクラスで宣言された友元関数は、閉じたクラスではなくネストされたクラスの範囲内とみなされます.したがって、友元関数には、閉じたクラスのメンバーまたはメンバー関数への特定のアクセス権はありません.友元関数のネストされたクラスで宣言された名前を使用する必要があり、友元関数がファイル範囲内で定義されている場合は、次のように限定されたタイプ名を使用します.

// friend_functions_and_nested_classes.cpp

#include 

enum
{
  sizeOfMessage = 255
};

char *rgszMessage[sizeOfMessage];

class BufferedIO
{
public:
  class BufferedInput
  {
  public:
    friend int GetExtendedErrorStatus();
    static char *message;
    static int messageSize;
    int iMsgNo;
  };
};

char *BufferedIO::BufferedInput::message;
int BufferedIO::BufferedInput::messageSize;

int GetExtendedErrorStatus()
{
  int iMsgNo = 1; // assign arbitrary value as message number

  strcpy_s( BufferedIO::BufferedInput::message,
       BufferedIO::BufferedInput::messageSize,
       rgszMessage[iMsgNo] );

  return iMsgNo;
}

int main()
{
}


次のコードは、友元関数として宣言された関数GetExtendedErrorStatusを示しています.ファイル範囲で定義された関数で、メッセージを静的配列からクラスメンバーにコピーします.GetExtendedErrorStatusのより良い実装は、次のように宣言されていることに注意してください.

int GetExtendedErrorStatus( char *message )

前のインタフェースでは、多くのクラスが、エラーメッセージをコピーするメモリの場所を渡すことで、この関数のサービスを使用できます.