甲class或struct还可以包含另一个class/struct内部本身的定义,这被称为“嵌套类”; 在这种情况下,包含类称为“封闭类”。嵌套类定义被认为是封闭类的成员,但在其他方面则是单独的。
struct Outer { struct Inner { }; };
从封闭类的外部,可以使用范围运算符访问嵌套类。但是,在封闭类的内部,可以使用没有限定符的嵌套类:
struct Outer { struct Inner { }; Inner in; }; // ... Outer o; Outer::Inner i = o.in;
与非嵌套class/一样struct,成员函数和静态变量可以在嵌套类内或在封闭的名称空间中定义。但是,由于它们被认为是与嵌套类不同的类,因此无法在封闭类中定义它们。
// 坏。 struct Outer { struct Inner { void do_something(); }; void Inner::do_something() {} }; // 好。 struct Outer { struct Inner { void do_something(); }; }; void Outer::Inner::do_something() {}
与非嵌套类一样,嵌套类可以在以后直接声明和定义,前提是在直接使用之前对其进行了定义。
class Outer { class Inner1; class Inner2; class Inner1 {}; Inner1 in1; Inner2* in2p; public: Outer(); ~Outer(); }; class Outer::Inner2 {}; Outer::Outer() : in1(Inner1()), in2p(new Inner2) {} Outer::~Outer() { if (in2p) { delete in2p; } }
在C ++ 11之前,嵌套类只能static从封闭的类中访问类型名称,成员和枚举数。封闭类中定义的所有其他成员是禁止进入的。
从C ++ 11开始,嵌套类及其成员被视为friend封闭类的成员,并且可以根据通常的访问规则来访问其所有成员。如果嵌套类的成员需要能够评估封闭类的一个或多个非静态成员,则必须为它们传递一个实例:
class Outer { struct Inner { int get_sizeof_x() { return sizeof(x); // 合法(C ++ 11):x未评估,因此不需要实例。 } int get_x() { return x; // 非法:没有实例就无法访问非静态成员。 } int get_x(Outer& o) { return o.x; // 合法(C ++ 11):作为Outer的成员,Inner可以访问私有成员。 } }; int x; };
相反,封闭类不会被视为嵌套类的朋友,因此,如果未明确授予其权限,则无法访问其私有成员。
class Outer { class Inner { // 朋友班外 int x; }; Inner in; public: int get_x() { return in.x; // 错误:int Outer :: Inner :: x是私有的。 // Uncomment "friend" line above to fix. } };
嵌套类的朋友不会自动视为封闭类的朋友;如果他们也需要成为封闭类的朋友,则必须分别声明。相反,由于封闭类不会自动被视为嵌套类的朋友,因此封闭类的朋友也不会被视为嵌套类的朋友。
class Outer { friend void barge_out(Outer& out, Inner& in); class Inner { friend void barge_in(Outer& out, Inner& in); int i; }; int o; }; void barge_in(Outer& out, Outer::Inner& in) { int i = in.i; // 好。 int o = out.o; // 错误:int Outer :: o是私有的。 } void barge_out(Outer& out, Outer::Inner& in) { int i = in.i; // 错误:int Outer :: Inner :: i是私有的。 int o = out.o; // 好。 }
与所有其他类成员一样,嵌套类只有在具有公共访问权限的情况下才能从类外部进行命名。但是,只要您未明确命名它们,都可以访问它们,而不论访问修饰符是什么。
class Outer { struct Inner { void func() { std::cout << "I have no private taboo.\n"; } }; public: static Inner make_Inner() { return Inner(); } }; // ... Outer::Inner oi; // 错误:外部::内部是私有的。 auto oi = Outer::make_Inner(); // 好。 oi.func(); // 好。 Outer::make_Inner().func(); // 好。
您也可以为嵌套类创建类型别名。如果封闭类中包含类型别名,则嵌套类型和类型别名可以具有不同的访问修饰符。如果类型别名在封闭类的外部,则它要求嵌套类typedef或其嵌套类是公共的。
class Outer { class Inner_ {}; public: typedef Inner_ Inner; }; typedef Outer::Inner ImOut; // 好。 typedef Outer::Inner_ ImBad; // 错误。 // ... Outer::Inner oi; // 好。 Outer::Inner_ oi; // 错误。 ImOut oi; // 好。
与其他类一样,嵌套类既可以从其他类派生也可以从其他类派生。
struct Base {}; struct Outer { struct Inner : Base {}; }; struct Derived : Outer::Inner {};
通过允许程序员根据需要更新嵌套的类,这在封闭类是从另一个类派生的情况下很有用。可以与typedef结合使用,以为每个封闭类的嵌套类提供一致的名称:
class BaseOuter { struct BaseInner_ { virtual void do_something() {} virtual void do_something_else(); } b_in; public: typedef BaseInner_ Inner; virtual ~BaseOuter() = default; virtual Inner& getInner() { return b_in; } }; void BaseOuter::BaseInner_::do_something_else() {} // --- class DerivedOuter : public BaseOuter { //注意使用合格的typedef;BaseOuter :: BaseInner_是私有的。 struct DerivedInner_ : BaseOuter::Inner { void do_something() override {} void do_something_else() override; } d_in; public: typedef DerivedInner_ Inner; BaseOuter::Inner& getInner() override { return d_in; } }; void DerivedOuter::DerivedInner_::do_something_else() {} // ... // 调用BaseOuter :: BaseInner _ :: do_something(); BaseOuter* b = new BaseOuter; BaseOuter::Inner& bin = b->getInner(); bin.do_something(); b->getInner().do_something(); // 调用DerivedOuter :: DerivedInner _ :: do_something(); BaseOuter* d = new DerivedOuter; BaseOuter::Inner& din = d->getInner(); din.do_something(); d->getInner().do_something();
在上述情况下,BaseOuter和分别DerivedOuter提供成员类型InnerasBaseInner_和DerivedInner_。这允许在不破坏封闭类的接口的情况下派生嵌套类型,并允许嵌套类型被多态使用。