ネストしたクラス
提供: cppreference.com
class/struct または union の宣言は別のクラス内に現れても構いません。 そのような宣言はネストしたクラスを宣言します。
説明
ネストしたクラスの名前は囲っているクラスのスコープに存在し、ネストしたメンバのメンバ関数からの名前探索はネストしたクラスのスコープを調べた後、囲っているクラスのスコープを訪問します。 囲っているクラスのいかなるメンバとも同様に、ネストしたクラスは囲っているクラスがアクセスを持つすべての名前 (プライベートなもの、プロテクテッドなもの、など) へのアクセスを持ちますが、それ以外の点では独立しており、囲っているクラスの this ポインタへの特別なアクセスは持ちません。
| ネストしたクラス内の宣言は、囲っているクラスの型名、静的メンバ、および列挙子のみを使用できます。 | (C++11未満) |
|
ネストしたクラス内の宣言は、非静的メンバのための通常の使用方法のルールに従って、囲っているクラスのあらゆるメンバを使用できます。 |
(C++11以上) |
int x,y; // グローバル変数。
class enclose { // 囲っているクラス。
int x; // 注: プライベートメンバ。
static int s;
public:
struct inner { // ネストしたクラス。
void f(int i) {
x = i; // エラー、インスタンスなしで非静的メンバ enclose::x に書き込むことはできません。
int a = sizeof x; // C++11 未満ではエラー。
// C++11 では OK。 sizeof の被演算子は未評価であり、
// 非静的メンバ enclose::x のこの使用方法は許されます。
s = i; // OK、静的メンバ enclose::s に代入できます。
::x = i; // OK、グローバル変数 x に代入できます。
y = i; // OK、グローバル変数 y に代入できます。
}
void g(enclose* p, int i) {
p->x = i; // OK、 enclose::x への代入。
}
};
};
ネストしたクラス内で定義されるフレンド関数は、たとえネストしたクラス内で定義されるメンバ関数の本体からの名前探索が囲っているクラスのプライベートメンバを発見できる場合でも、囲っているクラスのメンバへの特別なアクセスを持ちません。
ネストしたクラスのメンバのクラス外定義は囲っているクラスの名前空間内に現れます。
struct enclose {
struct inner {
static int x;
void f(int i);
};
};
int enclose::inner::x = 1; // 定義。
void enclose::inner::f(int i) {} // 定義。
ネストしたクラスは、前方宣言し、後で (同じ囲っているクラス本体内またはその外側のいずれかで) 定義することができます。
class enclose {
class nested1; // 前方宣言。
class nested2; // 前方宣言。
class nested1 {}; // ネストしたクラスの定義。
};
class enclose::nested2 { }; // ネストしたクラスの定義。
ネストしたクラスの宣言はメンバアクセス指定子に従います。 囲っているクラスのスコープの外側でプライベートメンバクラスを表すことはできません (そのクラスのオブジェクトを操作することはできるかもしれませんが)。
class enclose {
struct nested { // プライベートメンバ。
void g() {}
};
public:
static nested f() { return nested{}; }
};
int main()
{
//enclose::nested n1 = enclose::f(); // エラー、「nested」はプライベートです。
enclose::f().g(); // OK、「nested」という名前は使っていません。
auto n2 = enclose::f(); // OK、「nested」という名前は使っていません。
n2.g();
}
参考文献
- C++11 standard (ISO/IEC 14882:2011):
- 9.7 Nested class declarations [class.nest]
- C++98 standard (ISO/IEC 14882:1998):
- 9.7 Nested class declarations [class.nest]