C++: const 限定符
《C++ Primer》读书笔记。
基本作用
const
对象创建后,值不能再改变。
- 初始化:
1 2 3
int i = 42; const int ci = i; // 正确:i 的值被拷贝给了 ci int j = ci; // 正确: ci 的值被拷贝给了 j
- 默认情况下,
const
对象仅在文件内有效。 - 需要文件间共享时,使用
extern
关键字。1 2 3 4
// file_1.cc 定义并初始化另外一个常量,该常量能被其他文件访问 extern const int bufSize = fcn(); // file_1.h 头文件 extern const int bufSize; // 与 file_1.cc 中定义的 bufSize 是同一个
对常量的引用 (reference to const)
与普通引用不同,对常量的引用不能被用于修改其所绑定的对象。
1
2
3
4
const int ci = 1024
const int &r1 = ci; // 正确:引用及其对应的对象都是常量
r1 = 42; // 错误:r1 是对常量的引用
int &r2 = ci; // 错误:试图让一个非常量引用指向一个常量对象
临时量对象:
1
2
3
4
5
double dval = 3.14;
const int &ri = dval;
/* ======= 等价于 ======= */
const int temp = dval;
const int &ri = temp;
常量引用的对象本身可以不是一个常量。
1
2
3
4
5
int i = 42;
int &r1 = i;
const int &r2 = i;
r1 = 0; // 正确:可以通过 r1 修改 i 的值
r2 = 0; // 错误:不允许通过 r2 修改 i 的值
指针和 const
- 指向常量的指针 (pointer to const):不能改变其所指的对象。想存放常量对象的地址,只能使用指向常量的指针。
1 2 3 4
const double pi = 3.14; double *ptr = π // 错误:ptr 是一个普通指针 const double *cptr = π // 正确: cptr 可以指向一个双精度常量 *cptr = 42; // 错误:不能给 *cptr 赋值
指向常量的指针所指的对象可以是一个非常量。
1 2
double dval = 3.14; cptr = &dval; // 正确:注意不能通过 cptr 改变 dval 的值
- 常量指针 (const pointer):指针本身为常量。初始化完成后,它的值不能再改变。书写方式为把
*
放在const
关键字前。1 2 3 4
int errNumb = 0; int *const curErr = &errNumb; // curErr 将一直指向 errNumb const double pi = 3.14159; const double *const pip = π // pip 是一个指向常量对象的常量指针
顶层 const
- 顶层 const (top-level const):指针本身是常量。更一般地,表示任意对象是常量,适用于任何数据类型。
- 底层 const (low-level const):指针所指的对象是一个常量。更一般地,通常和指针、引用等复合类型的基本类型部分有关。
一些例子:
1
2
3
4
5
6
int i = 0;
int *const p1 = &i; // 顶层 const
const int ci = 42; // 顶层 const
const int *p2 = &ci // 底层 const
const int *const p3 = p2 // 靠右的 const 是顶层 const,靠左的是底层 const
const int &r = ci; // 用于声明引用的 const 都是底层 const
- 执行对象的拷贝操作时,顶层 const 不受影响。但底层 const 受限制:拷入和拷出的对象必须具有相同的底层 const 资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转换成常量,反之则不行。
1 2 3 4 5 6 7 8
i = ci // 正确:ci 为顶层 const,对此操作无影响 p2 = p3 // 正确:p2 和 p3 所指类型相同,p3 顶层 const 部分不受影响 int *p = p3; // 错误:p3 包含底层 const 的定义,而 p 不包含 p2 = p3; // 正确:p2 和 p3 都是底层 const p2 = &i; // 正确:int* 能转换成 const int* int &r = ci; // 错误:普通的 int& 不能绑定到 int 常量上 const int &r2 = i; // 正确:const int& 可以绑定到一个普通 int 上
const 形参和实参
- 用实参初始化形参时会忽略顶层 const,也就是形参的顶层 const 被忽略了。
1 2 3
// 以下两个函数定义重复 void fcn(const int i) {} void fcn(int i) {}
- 指针或引用形参与 const
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
void reset(int *ip) { *ip = 0; } void reset(int &i) { i = 0; } int i = 0; const int ci = i; string::size_type ctr = 0; reset(&i); // 正确:调用形参类型是 int* 的 reset 函数 reset(&ci); // 错误:不能用指向 const int 对象的指针初始化 int* reset(i); // 正确:调用形参是 int& 的 reset 函数 reset(ci); // 错误:不能把普通引用绑定到 const 对象 ci 上 reset(42); // 错误:不能把普通引用绑定到字面值上 reset(ctr); // 错误:类型不匹配,ctr 是无符号类型
This post is licensed under CC BY 4.0 by the author.