クラスのスコープ内で別のクラスを宣言できます。 このようなクラスは "入れ子にされたクラス" と呼ばれます。入れ子にされたクラスは外側のクラスのスコープ内にあるとみなされ、そのスコープ内で使用できます。 すぐ外側のスコープ以外のスコープから入れ子のクラスを参照するには、完全修飾名を使用する必要があります。
次に、入れ子のクラスを宣言する方法を示します。
// 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
には、入れ子になったクラス BufferedIO::BufferedInput
または BufferedIO::BufferedOutput
のメンバー関数によって直接アクセスできます (good
関数を参照)。
Note
入れ子のクラスは、クラス スコープ内の型のみ宣言します。 入れ子のクラスに含まれるオブジェクトは作成されません。 前の例では、入れ子になった 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()
{
}
前の例では、関数名の宣言に、修飾型名構文が使用されています。 宣言:
BufferedIO::BufferedInput::read()
"BufferedIO
クラスのスコープ内にある BufferedInput
クラスのメンバーである read
関数" を意味します。この宣言では修飾型名構文が使用されるため、次の形式のコンストラクトが可能です。
typedef BufferedIO::BufferedInput BIO_INPUT;
int BIO_INPUT::read()
上記の宣言は、前の例と等価ですが、クラス名の代わりに typedef
名を使用します。
入れ子にされたクラスのフレンド関数
入れ子になったクラスで宣言された friend 関数は、それを囲んでいるクラスではなく、入れ子になったクラスのスコープ内にあると見なされます。 したがって、フレンド関数は、外側のクラスのメンバー関数に対する特別なアクセス特権を取得しません。 フレンド関数がファイルのスコープで定義されている場合に、そのフレンド関数の入れ子になったクラスで宣言されている名前を使用するには、次のように修飾型名を使用します。
// friend_functions_and_nested_classes.cpp
#include <string.h>
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 )
前のインターフェイスを使用すると、いくつかのクラスは、エラー メッセージのコピー先のメモリ位置を渡すことによって、この関数のサービスを使用できます。