用关键字const对变量的类型加以限定,可以将变量定义成一个常量。因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化
const int bufsize = 512;
//bufsize被定义为一个常量,任何试图为bufsize赋值的行为都会引发错误
const int i = get_size(); //正确,运行时初始化
const int j = 42; //正确:编译时初始化
const int k; //错误:k是一个未初始化的常量
如果用一个对象去初始化另外一个对象,则它们是不是const都无关紧要
int i = 42;
const int ci = i; //正确:i的值被拷贝给了ci
int j = ci; //正确:ci的值被拷贝给了j
当用 ci 去初始化 j 时,根本无需在意ci是不是一个常量。拷贝一个对象的值并不会改变它,一旦拷贝完成,新的对象就和原来的对象没有什么关系了
默认状态下,const对象仅在文件内有效
当多个文件中出现了同名的const变量时,其实等同于在不同文件中分别定义了独立的变量
如果const对象需要在不同文件之间进行共享,需要在const对象的声明和定义前添加extern关键字。在一个文件中定义const,而在其他多个文件中声明并使用
extern 表示变量或函数的定义在别的文件中,提示编译器遇到此变量或函数,在其他模块中寻找定义
//file_1.cc定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufsize = fcn();
//file_1.h头文件
extern const int bufsize; //与file_1.cc中定义的bufsize是同一个
const的引用
可以将引用绑定在const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用(reference to const)。与普通引用不同的是,对常量的引用不能够修改引用所绑定的对象
const int ci = 1024;
const int &r1 = ci; //正确:引用及其对象都是常量
r1 = 42; //错误:r1是对常量的引用
int &r2 = ci; //错误:试图让一个非常量引用指向一个常量引用
引用的类型必须与其所引用的对象一致,但是有两个例外。第一种例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转化成引用的类型即可。
int i = 42;
const int &r1 = i; //允许将const int &绑定到一个普通int对象
const int &r2 = 42; //正确:r2是一个常量引用
const int &r3 = r1 * 2; //正确:r3是一个常量引用
int &r4 = r1 * 2; //错误:r4是一个普通的常量引用
指针与const
指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针:
const double pi = 3.14;
double *ptr = π //错误:ptr只是一个普通指针
const double *cptr = π //正确:cptr可以指向一个双精度的常量
*cptr = 42; //错误:不能给*cptr赋值
//允许一个指向常量的指针指向一个非常量的对象
double dval = 3.14;
cptr = &dval; //正确,但不能通过cptr改变dval的值
const指针
指针是对象引用不是,允许将指针本身定义为const常量。常量指针必须初始化,而且一旦初始化完成,则它的值(存放在指针中的地址)就不能再改变了,即不变的是针本身而非指向的那个值
int errNumb = 0;
int *const curErr = &errNumb; //cuErr将一直指向errNumb
const double pi = 3.14;
const double *const pip = π //pip是指向常量对象的常量指针
指针本身是一个常量并不意味着不能通过指针修改其所指对象的值,能否这样做依赖于所指对象的类型。例如:pip是一个指向常量对象的常量指针,pip所指的对象值还是pip自己存储的那个地址都不改变。相反的,curErr指向的是一个一般的非常量整型类型,可以通过修改curErr所指向的值来修改errNumb
*pip = 2.22; //错误
*curErr = 0; //正确
顶层const和底层const
顶层const表示指针本身是一个常量,而用名词底层const表示所指对象是一个常量
const int *const p3 = p2; //靠右的const是顶层const,靠左的是底层const
const int &r = ci; //用于声明引用的const都是底层const
在执行对象的拷贝时,常量是顶层const,还是底层const区别明显。其中,顶层const不受什么影响,而底层const指向拷贝操作时,拷入和拷出的对象必须具有相同的底层const资格。一般来说,非常量可以转化为常量,反之则不行