Namespaces
Variants

Nested classes

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

クラス/構造体または共用体の宣言は、他のクラス内に現れることがあります。そのような宣言は ネストされたクラス を宣言します。

説明

ネストされたクラスの名前は、外側のクラスのスコープ内に存在し、ネストされたクラスのメンバー関数からの名前探索は、ネストされたクラスのスコープを調べた後、外側のクラスのスコープを参照します。外側のクラスの任意のメンバーと同様に、ネストされたクラスは外側のクラスがアクセス可能なすべての名前(private、protectedなど)にアクセスできますが、それ以外は独立しており、外側のクラスの this pointer への特別なアクセス権はありません。ネストされたクラス内の宣言では、非静的メンバーに対する 通常の使用規則 に従って、外側のクラスのあらゆるメンバーを使用できます。

int x, y; // グローバル変数
class enclose // 外側のクラス
{
    // 注: privateメンバ
    int x;
    static int s;
public:
    struct inner // ネストされたクラス
    {
        void f(int i)
        {
            x = i; // エラー: インスタンスなしでは非staticなenclose::xに書き込めない
            int a = sizeof x; // C++11までエラー、
                              // C++11ではOK: sizeofのオペランドは評価されないため、
                              // 非staticなenclose::xのこの使用は許可される
            s = i;   // OK: staticなenclose::sに代入可能
            ::x = i; // OK: グローバルxに代入可能
            y = i;   // OK: グローバルyに代入可能
        }
        void g(enclose* p, int i)
        {
            p->x = i; // OK: enclose::xに代入
        }
    };
};

Friend ネストされたクラス内で定義されたフレンド関数は、たとえネストされたクラス内で定義されたメンバー関数の本体からのルックアップが外側のクラスのプライベートメンバーを見つけることができる場合でも、外側のクラスのメンバーに対する特別なアクセス権を持ちません。

ネストされたクラスのメンバーのクラス外定義は、外側のクラスの名前空間内に現れます:

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 {}; // ネストされたクラスの定義

ネストされたクラス宣言は メンバーアクセス 指定子に従います。privateメンバークラスは、外側のクラスのスコープ外では名前を参照できませんが、そのクラスのオブジェクトを操作することは可能です:

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++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 45 C++98 ネストされたクラスのメンバーは
外側のクラスとそのフレンドにアクセスできない
外側のクラスの他のメンバーと同じ
アクセス権を持つ
(CWG 問題 #8 および #10 も解決)

参考文献

  • C++23規格 (ISO/IEC 14882:2024):
  • 11.4.12 ネストされたクラス宣言 [class.nest]
  • C++20 標準 (ISO/IEC 14882:2020):
  • 11.4.10 ネストされたクラス宣言 [class.nest]
  • C++17規格 (ISO/IEC 14882:2017):
  • 12.2.5 ネストされたクラス宣言 [class.nest]
  • C++14標準 (ISO/IEC 14882:2014):
  • 9.7 ネストしたクラス宣言 [class.nest]
  • C++11標準 (ISO/IEC 14882:2011):
  • 9.7 ネストしたクラス宣言 [class.nest]
  • C++98標準 (ISO/IEC 14882:1998):
  • 9.7 ネストしたクラス宣言 [class.nest]