嵌套类

来自cppreference.com
< cpp‎ | language

class/structunion 的声明可以在另一个类中出现。这种声明声明一个嵌套类(nested class)

解释

嵌套类的名字在它的外围类作用域中存在,而且从嵌套类的成员函数中进行名字查找会在检测嵌套类的作用域后访问外围类的作用域。与其外围类的任何成员相似,嵌套类也拥有所有外围类拥有访问权的名字(私有、受保护等)的访问权,但其他方面它是独立的,而且对外围类的 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 = e.f(); // 错误:'nested' 是私有的
 
    enclose::f().g();       // OK:没有指名 'nested'
    auto n2 = enclose::f(); // OK:没有指名 'nested'
    n2.g();
}

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 45 C++98 嵌套类的成员无法访问外围类及其友元 它们和外围类的其他成员有相同的访问权限
(同时解决了 CWG 的8号和10号问题)

引用

  • C++11 标准(ISO/IEC 14882:2011):
  • 9.7 Nested class declarations [class.nest]
  • C++98 标准(ISO/IEC 14882:1998):
  • 9.7 Nested class declarations [class.nest]