概述
有时我们希望定义这样一张变量,它的值不能被改变。那么,可以用关键字const对变量的类型加以限定。
const int bufSize = 512; //输入缓冲区的大小
const对象一旦创建后其值就不能再改变,因此const对象必须初始化。
const int i = get_size(); //正确
const int j = 42; //正确
const int k; //错误:k是一个未经初始化的常量
初始化和const
只能在const类型的对象上执行不改变其内容的操作:
①eg.const int 和普通的 int 一样都能参与算术运算
②初始化。利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要
int i = 42;
const int ci = i; //正确:i的值被拷贝给了ci
int j = ci; //正确:ci的值被拷贝给了j
默认状态下,const对象仅在文件内有效
多个文件中出现了同名的const变量,其实等同于在不同文件中分别定义了独立的变量。
解决办法:对于 const 变量不管是声明还是定义都添加 extern 关键字,这样只需定义一次就可以了:
//file_1.cc定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufSize = fcn();
//file_1.h头文件
extern const int bufSize; //与file_1.cc中定义的 bufSize 是同一个
如果想在多个文件之间共享const对象,必须在变量的定义之前加上extern关键字
const的引用
“对const的引用”简称为”常量引用“。
与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象:
const int ci = 1024;
cocst int &r1 = ci; //正确:引用及其对应的对象都是常量
r1 = 42; //错误:r1是对常量的引用
int &r2 = ci; //错误:试图让一个非常量引用指向一个常量对象
引用的对象是常量还是非常量可以决定其所能参与的操作,却无论如何都不会影响到引用和对象的绑定关系本身。
初始化和对 const 的引用
引用的类型必须与其所引用的对象的类型一致,但,有两个例外:
①在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式:
int i = 41;
const int &r1 = i; //允许将 const int& 绑定到一个普通 int 对象上
const int &r2 = 41; //正确:r1是一个常量引用
const int &r3 = r1 * 2; //正确:r3是一个常量引用
int &r4 = r1 * 2; //错误:r4是一个普通的非常量引用
当一个常量引用被绑定到另外一种类型上时:
double dval = 3.14;
const int &ri = dval;
此处 ri 引用了一个 int 型的数,但 dval 却是一个双精度浮点数。因此为了确保让 ri 绑定一个整数,编译器把上述代码变成如下形式:
const int temp = dval; //让双精度浮点数生成一个临时的整型常量
const int &ri = temp; //让 ri 绑定这个临时量
临时量(对象):当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。
对 const 的引用可能引用一个并非 const 的对象
因此,允许通过其他途径改变它的值:
int i = 42;
int &r1 = i; //引用r1绑定对象i
const int &r2 = i; //r2也绑定对象i,但是不允许通过r2修改i的值
r1 = 0; //r1并非常量,i的值修改为0
r2 = 0; //错误:r2是一个常量引用
指针和const
类似于常量引用,指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针:
const double pi = 3.14;
double *ptr = π //错误:ptr是一个普通指针
const double *cptr = π //正确:cptr可以指向一个双精度常量
*cptr = 42; //错误:不能给*cptr赋值
指针的类型必须与其所指对象的类型一致,但有两个例外:
①允许令一个指向常量的指针指向一个非常量对象
和常量引用类似
const指针
把*放在 const 关键字之前用以说明指针是一个常量。含义是:不变的是指针本身的值而非指向的那个值。
int err = 0;
int *const cur = &err ; //cur将一直指向err
const double pi = 3.14159;
const double *const pip = &pi ; //pip是一个指向常量对象的常量指针
顶层const
顶层const表示指针本身是个常量
底层const表示指针所指的对象是一个常量
int i = 0;
int *const p1 = &i; //不能改变p1的值,是顶层const
const int ci = 42; //不能改变ci的值,顶层const
const int *p2 = &ci; //允许改变p2的值,底层const
当执行对象的拷贝工作时,常量是顶层const还是底层const区别明显:
顶层const不受什么影响;
底层const有限制:拷入和拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换。一般来说,非常量可以转化为常量,反之则不行