目录
基本定义
内部类也成为嵌套类,英文名叫做nested classes。接下来我们统称内部类。
核心规则:
- 内部类是声明在另外一个类内部的类、结构体或者联合体。就相当于在一个类里面又定义了一个类,外面这一层称为外围类,或者叫做外部类,英文名是enclosing class。
- 内部类的名字仅仅存在于外部类的作用域中,也就是想要用这个名字,就得像std::string一样使用这个类,只不过这里指定的不是命名空间,而是外部类的类域。例如: OuterClass::InnerClass。
- 因为在外部类的里面,因此这里会涉及到很多类成员访问的原则,后续讲解。
代码示例:
cpp
#include <iostream>
#include <string>
std::string str = "全局作用域str";
class Outer {
private:
std::string str = "Outer的私有str";
public:
class Inner {
public:
std::string str = "Inner的公有str";
void show_str() {
std::cout << str << std::endl;
}
};
void show_str() {
std::cout << str << std::endl;
}
};
int main() {
// 创建一个Outer类对象
Outer outer_class;
// 创建一个Inner类对象
Outer::Inner inner_class;
outer_class.show_str();
inner_class.show_str();
return 0;
}
输出:
cpp
Outer的私有str
Inner的公有str
如果你想在内部类或者外部类中访问全局变量的str,只需要指定全局域就可以:
cpp
std::string str = "全局作用域str";
class Outer {
private:
std::string str = "Outer的私有str";
public:
class Inner {
public:
std::string str = "Inner的公有str";
void show_str() {
std::cout << str << std::endl;
// 指定全局作用域 -- ::str
std::cout << ::str << std::endl;
}
};
void show_str() {
std::cout << str << std::endl;
std::cout << ::str << std::endl;
}
};
嵌套类对外部类的访问权限
既然是在类的内部定义的,那么必然会涉及到权限相关的问题。
cpp
#include <iostream>
#include <string>
std::string str = "全局作用域str";
class Outer {
private:
static std::string str_static;
std::string private_str = "Outer的私有str";
public:
std::string public_str = "Outer的公有str";
class Inner {
public:
void show_str(Outer* out = nullptr) {
// 直接访问静态变量
std::cout << str_static << std::endl;
// 访问out的private str
std::cout << out->private_str << std::endl;
// 访问out的public str
std::cout << out->public_str << std::endl;
// 访问全局域的str
std::cout << ::str << std::endl;
}
};
};
std::string Outer::str_static("Outer的static私有str");
int main() {
Outer outer_obj;
Outer::Inner inner_obj;
inner_obj.show_str(&outer_obj);
return 0;
}
输出:
bash
Outer的static私有str
Outer的私有str
Outer的公有str
全局作用域str
从上述代码可以看到,内部类是可以访问外部类定义的public, private和static成员变量的。只不过需要注意的是,访问外部类的非静态成员变量,首先需要一个外部类的对象才可以访问,只有静态的外部类的成员变量才可以直接通过类域在内部类中访问。
访问外部类的成员变量的时候,必须要在内存里面现有一个外部类的对象,你才可以访问其成员变量,因为有地址你才可以访问。你在内部类中访问外部类的成员变量,内部类的成员函数传递的是内部类的this指针给内部类的成员函数,并没有传递外部类的this指针,因此需要显式传递外部类的对象的地址。
sizeof(外部类)
对一个定义类内部类的外部类进行sizeof操作会发生什么?
cpp
#include <iostream>
#include <string>
class Outer {
public:
int x;
int y;
class Inner {
public:
int a;
int b;
};
};
int main() {
Outer outer_obj;
std::cout << sizeof(outer_obj) << std::endl;
return 0;
}
结果输出:8
可以得知,内部类的定义在编译之后运行时是不占用栈空间的,因为在构建外部类对象的时候,并不会生成一个内部类的对象,它只是定义在外部类中,创建外部类对象并不会同时创建一个内部类对象。
内部类友元函数的权限
在内部类中定义的友元函数没有对外部类成员的特殊访问权限,友元仅仅只针对当前类,无法从内部类,延伸到外部类。
下面是错误的定义:
cpp
#include <iostream>
#include <string>
class Outer {
private:
int x = 10;
int y = 20;
class Inner {
public:
friend void access_outer(Outer* out);
};
public:
};
void access_outer(Outer* out) {
std::cout << out->x + out->y << std::endl;
return;
}
int main() {
Outer outer_obj;
access_outer(&outer_obj);
return 0;
}
这个定义中,虽然access_outer是Inner类的友元函数,它可以访问Inner内的私有成员,但即使如此,它依旧访问不了Outer中的私有成员:

如果想访问,那么需要做出如下修改:
- 将友元声明挪至外部类中
- 将外部类的私有成员改为公有(public)
内部类函数类外实现和延迟声明
这个就是一个声明和定义分离,没啥好说的,看代码:
cpp
#include <iostream>
class Enclose {
public:
class Inner {
static int static_x; // 静态成员声明
void f(int i); // 成员函数声明
};
};
// 1. 嵌套类静态成员的类外定义
int Enclose::Inner::static_x = 100;
// 2. 嵌套类成员函数的类外定义
void Enclose::Inner::f(int i) {
std::cout << "Enclose::Inner::f called with i = " << i << std::endl;
}
注意在外部类外定义内部类的函数的时候,需要先加外部类域,然后加内部类域,形如:
Outer_class::Inner_Class::function(参数列表) { ... } ;
所谓延迟声明,也就是可以先声明,然后再定义:
cpp
class Enclose {
class Nested1; // 前向声明 Nested1
class Nested2; // 前向声明 Nested2
// 1. 在外部类内部定义 Nested1
class Nested1 {
public:
void show() { cout << "Nested1 defined inside Enclose" << endl; }
};
};
// 2. 在外部类外部定义 Nested2
class Enclose::Nested2 {
public:
void show() { cout << "Nested2 defined outside Enclose" << endl; }
};
在enclose类中,先声明了Nested1和Nested2,然后在外部类内定义了Nested1,在外部类外定义了Nested2(外部定义注意加外部类域)。
访问限定符对内部类的影响
作为外部类的内部类定义,其自身可见性受到private等关键字的影响,例如:
下面是一个错误的示范:
cpp
#include <iostream>
using namespace std;
class Outer {
private:
class Inner { // 私有嵌套类
void g() { cout << "Inner::g() called" << endl; }
};
public:
static Inner f() { return Inner{}; }
};
int main() {
Outer::Inner inner_obj;
}
无法访问Outer中的Inner:

总结
| 规则维度 | 核心要点 |
|---|---|
| 作用域与名字查找 | 嵌套类名字在外部类作用域内,查找顺序:嵌套类 → 外部类 → 全局 |
| 访问外部类非静态成员 | 必须通过外部类对象 / 指针 / 引用 |
| 访问外部类静态成员 | 可直接访问 |
| 嵌套类中友元函数 | 无外部类成员特殊访问权 |
| 类外定义 | 需用 外部类::嵌套类::成员 语法 |
| 前向声明 | 可先声明,后在外部类内 / 外定义 |
| 可见性(访问限定符) | private 嵌套类外部无法命名,但可通过接口操作对象 |