作用域、持续时间和链接的概念引起了很多困惑,所以我们将额外花一节课来总结所有内容。其中有些内容我们尚未涉及,它们只是为了完整性/供以后参考而放在这里。
作用域总结
标识符的作用域决定了在源代码中何处可以访问该标识符。
- 具有块(局部)作用域的变量只能从声明点到声明它们的块的末尾(包括嵌套块)访问。这包括:
- 局部变量
- 函数参数
- 在块内声明的程序定义类型(例如枚举和类)
- 具有全局作用域的变量和函数可以从声明点到文件末尾访问。这包括:
- 全局变量
- 函数
- 在命名空间内或全局作用域中声明的程序定义类型(例如枚举和类)
持续时间总结
变量的持续时间决定了它何时创建和销毁。
- 具有自动持续时间的变量在定义时创建,并在它们所属的块退出时销毁。这包括:
- 局部变量
- 函数参数
- 具有静态持续时间的变量在程序开始时创建,并在程序结束时销毁。这包括:
- 全局变量
- 静态局部变量
- 具有动态持续时间的变量由程序员请求创建和销毁。这包括:
- 动态分配的变量
链接总结
标识符的链接决定了同一标识符在不同作用域中的声明是否引用相同的实体(对象、函数、引用等)。
局部变量没有链接。每个没有链接的标识符声明都引用一个唯一的对象或函数。
- 具有无链接的标识符意味着同一标识符的另一个声明引用一个唯一的实体。其标识符具有无链接的实体包括:
- 局部变量
- 在块内声明的程序定义类型标识符(例如枚举和类)
- 具有内部链接的标识符意味着同一翻译单元内同一标识符的声明引用相同的对象或函数。其标识符具有内部链接的实体包括:
- 静态全局变量(已初始化或未初始化)
- 静态函数
- Const 全局变量
- 匿名命名空间及其内部定义的任何内容
- 具有外部链接的标识符意味着整个程序中同一标识符的声明引用相同的对象或函数。其标识符具有外部链接的实体包括:
- 非静态函数
- 非 const 全局变量(已初始化或未初始化)
- Extern const 全局变量
- Inline const 全局变量
- 命名空间
如果具有外部链接的定义被编译到多个 .cpp 文件中(由于违反了单一定义规则),通常会导致重复定义链接器错误。此规则有一些例外(对于类型、模板、内联函数和变量)——我们将在以后的课程中讨论这些主题时进一步介绍它们。
另请注意,函数默认具有外部链接。它们可以通过使用 static 关键字设置为内部链接。
变量作用域、持续时间和链接总结
因为变量具有作用域、持续时间和链接,让我们用图表总结一下:
类型 | 示例 | 作用域 | 持续时间 | 链接 | 备注 |
---|---|---|---|---|---|
局部变量 | int x; | 块 | 自动 | 无 | |
静态局部变量 | static int s_x; | 块 | 静态 | 无 | |
动态局部变量 | int* x { new int{} }; | 块 | 动态 | 无 | |
函数参数 | void foo(int x) | 块 | 自动 | 无 | |
内部非 const 全局变量 | static int g_x; | 全局 | 静态 | 内部 | 已初始化或未初始化 |
外部非 const 全局变量 | int g_x; | 全局 | 静态 | 外部 | 已初始化或未初始化 |
内联非 const 全局变量 (C++17) | inline int g_x; | 全局 | 静态 | 外部 | 已初始化或未初始化 |
内部常量全局变量 | constexpr int g_x { 1 }; | 全局 | 静态 | 内部 | 必须初始化 |
外部常量全局变量 | extern const int g_x { 1 }; | 全局 | 静态 | 外部 | 必须初始化 |
内联常量全局变量 (C++17) | inline constexpr int g_x { 1 }; | 全局 | 静态 | 外部 | 必须初始化 |
前向声明总结
您可以使用前向声明来访问另一个文件中的函数或变量。声明变量的作用域与往常一样(全局变量的全局作用域,局部变量的块作用域)。
类型 | 示例 | 备注 |
---|---|---|
函数前向声明 | void foo(int x); | 仅原型,无函数体 |
非常量变量前向声明 | extern int g_x; | 必须未初始化 |
Const 变量前向声明 | extern const int g_x; | 必须未初始化 |
Constexpr 变量前向声明 | extern constexpr int g_x; | 不允许,constexpr 无法前向声明 |
constexpr 变量(隐式 const)可以使用 const 变量前向声明进行前向声明。通过前向声明访问时,该变量将被视为 const(而不是 constexpr)。
什么是存储类说明符?
当用作标识符声明的一部分时,static
和 extern
关键字称为存储类说明符。在这种上下文中,它们设置标识符的存储持续时间和链接。
C++ 支持 4 种活动的存储类说明符:
说明符 | 含义 | 注意 |
---|---|---|
extern | 静态(或 thread_local)存储持续时间和外部链接 | |
static | 静态(或 thread_local)存储持续时间和内部链接 | |
thread_local | 线程存储持续时间 | |
mutable | 即使包含类是 const,也允许修改对象 | |
auto | 自动存储持续时间 | 在 C++11 中已弃用 |
register | 自动存储持续时间并提示编译器放置在寄存器中 | 在 C++17 中已弃用 |
存储类说明符一词通常仅用于正式文档中。