内容思维导图

1. 单独编译
- 程序的三个组成部分
- 头文件:包含结构声明和函数原型。
- 源代码文件:包含函数定义代码。
- 源代码文件:包含调用函数代码。
- 头文件常包含的内容:
- 函数原型
- 使用
#define
或const
定义的符号常量 - 结构声明
- 类声明
- 模板声明
- 内联函数
- 文件名包含在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统中查找;如果文件名包含在双引号中,则编译器将首先查找当前的工作目录或源代码目录。
2. 存储持续性、作用域或链接性
-
C++3种不同的存储数据方案:
- 自动存储持续性:在函数定义中声明的变量(包括函数参数)的存储持续性为自动的。
- 静态存储持续性:在函数定义外定义的变量和使用关键字
static
定义的变量的存储持续性都为静态。 - 动态存储持续性:用
new
操作符分配的内存将一直存在,直到使用delete
操作符将其释放或程序结束为止。这种内存的存储持续性为动态,有时又称为自由存储(free store)。
-
作用域(scope)描述了名称在文件(翻译单元)的多大范围内可见。
-
C++使用关键字
register
来声明寄存器变量。因为寄存器变量存储在寄存器中,没有内存地址,因此不能将地址操作符用于寄存器变量。 -
静态持续变量的两个特征
- 未被初始化的静态变量的所有位都被设置为0。
- 只能使用常量表达式来初始化静态变量。
-
5种变量存储方式
存储描述 | 持续性 | 作用域 | 链接性 | 如何声明 |
---|---|---|---|---|
自动 | 自动 | 代码块 | 无 | 在代码块中(可使用关键字auto ) |
寄存器 | 自动 | 代码块 | 无 | 在代码块中,使用关键字register
|
静态、无链接性 | 静态 | 代码块 | 无 | 在代码块中,使用关键字static
|
静态、外部链接性 | 静态 | 文件 | 外部 | 在函数外面 |
静态、内部链接性 | 静态 | 文件 | 内部 | 在函数外面,使用关键字static
|
- 使用其他文件定义的外部变量(全局变量),必须在引用声明中使用关键字
extern
。 - 作用域解析符
::
放在变量前面表示使用变量的全局版本。 -
const
全局变量的链接性为内部,就像使用了static
说明符一样。如果希望某个常量的链接性为外部,可以使用extern
关键字来覆盖默认的内部链接性。
const int states = 50; // 链接性为内部
extern const int states = 50; // 链接性为外部
- C++函数默认情况下,链接性为外部的,但可使用关键字
static
将函数的链接性设置为内部,必须同时在原型和函数定义中使用该关键字。
// 内部链接函数
static int privateFunc(double x);
static int privateFunc(double x)
{
// implement function
}
- C++有一个“单定义规则”,即对于每一个非内联函数,程序中只能包含一个定义。
- C++要求同一个函数的所有内联定义都必须相同。
- 查找符号名称约定
extern "C" void spiff(int); // 使用C语言约定查找名称
extern void spiff(int); // 使用C++语言约定查找名称
extern "C++" void spiff(int); // 使用C++语言约定查找名称
- 通常,编译器使用3块独立的内存:一块用于静态变量(可再细分),一块用于自动变量,另外一块用于动态存储。
3. 布局new操作符
-
new
操作符的一种变体称为布局(placement)new
操作符
char buffer[200];
int *p1, *p2;
p1 = new int[20]; // 在堆分配内存
p2 = new (buffer) int[20]; // 在buffer中为p2分配存储
4. 名称空间
- 相关术语
- 声明区域(declaration region):可以在其中进行声明的区域。
- 潜在作用域(potential scope):变量的潜在作用域从声明点开始,到其声明区域的结尾。
- 作用域(scope):变量对程序而言可见的范围。
-
using
声明使特定的标识符可用,using
编译指令使整个名称空间可用。
namespace Jill
{
double fetch;
...
}
// 使用using声明将名称添加到局部声明区域,覆盖同名的全局变量
char fetch; // 全局变量
int main()
{
using Jill::fetch; // using声明
fetch = 5.0; // 给Jill::fetch赋值
::fetch = 'c'; // 给全局变量fetch赋值
}
// 使用using声明将名称添加到全局名称空间
using Jill::fetch;
int main()
{
fetch = 5.0;
}
// 1、全局声明区域使用using编译指令
#include <iostream>
using namespace Jill;
// 2、函数中使用using编译指令
void func1()
{
using namespace Jill;
...
}
-
using
编译指令与using
声明的区别:使用using
声明就像声明了相应的名称一样,如果名称在函数中存在,则不能使用using
声明导入相同的名称。但如果使用using
编译指令,将进行名称解析,只是局部名称将隐藏名称空间中的名称。
namespace Jill
{
double fetch;
}
int main()
{
using namespace Jill;
double fetch; // 隐藏Jill::fetch
using Jill::fetch; // 错误,名称已经存在
Jill::fetch = 5.0; // 通过作用域解析符::使用名称空间中的名称
}
-
using
编译指令是可传递的。
namespace Jill
{
double fetch;
}
namespace myth
{
using Jill::fetch;
using namespace elements; // 其中elements是一个名称空间
}
int main()
{
// 下面语句都指的是Jill名称空间中的fetch变量
Jill::fetch = 5.0;
myth::fetch = 5.0;
}
//--------------------------------
using namespace myth;
// 与下面语句等价
using namespace myth;
using namespace elements;
- 使用名称空间别名
namespace DicomImageDrawingLibrary
{
//...
}
namespace DIDL = DicomImageDrawingLibrary;
- 可以使用未命名名称空间的方法代替链接性为内部的静态变量。
namespace
{
int counts; // 静态存储,内部链接
}
- 名称空间的一些指导原则:
- 使用在已命名的名称空间中声明的变量,而不是使用外部全局变量。
- 使用在已命名的名称中间中声明的变量,而不是使用静态全局变量。
- 如果开发一个函数库或类库,将其放在一个名称空间中。
- 仅将编译指令
using
作为一种将旧代码转换为使用名称空间的权宜之计。 - 不要在头文件中使用
using
指令(包含头文件的顺序可能影响程序行为)。 - 导入名称时,首选使用作用域解析符或
using
声明的方法。 - 对于
using
声明,首选将其作用域设置为局部而不是全局。
网友评论