关键词const是什么含义?
const是只读变量,意味着不能对变量进行写入操作。
const int a; //a为常量
int const a; //a为常量
const int *a; //a为普通指针,指向的是const常量
int * const a; //a为常量指针,指向的是普通变量
int const * a const; //a为常量指针,指向的是const常量
本质:const在谁后面谁就不可修改,const在最前面则将其后移一位即可,二者等效
因为const变量一经初始化就不能被更改,所以const对象必须要初始化。该特征仅在执行改变操作时发生作用,其他如赋值、算术运算时根本无须在意它是不是一个常量。
一般const对象仅在文件内有效,如果需要多个文件共用,需要在声明和定义都添加上extern关键字。
//在file1.cpp定义并初始化,该变量能被其他文件访问
extern const int buffSize = 5;
//在file1.h头文件
extern const int buffSize;
1.对const的引用
const int ci = 1024;
const int &r1 = ci; //正确,引用和其对象都是常量
int &2 = ci; //错误,试图让一个非常量引用指向一个常量对象
int i = 42;
const int &r1 = i; //允许const int&绑定到一个普通int对象上
常量引用仅仅对引用可参与的操作作出了限定(不允许更改),对其引用对象本身是不是const并未规定。因此对象有可能是一个正常变量,但是不能通过引用(别名)去改变他。i可以通过其他途径去改变,比如i = 5这种,这种是没规定的。
2.指针和const
const double pi = 3.14; //常量,值不可变
double *ptr = π //错误,不能用普通指针指向常量
const double *cptr = π //正确
*cptr = 42; //错误,不可更改
允许令一个指向常量的指针指向非常量对象,但不能改变该常量的值,和引用类似。所谓指向常量的指针仅仅是要求不能通过该指针取改变常量的指,但没有规定不能用其他途径去改变。指向常量的指针或引用,不过是指针或引用“自以为是”,觉得自己指向了常量,所以自觉地不去改变所指对象的值。
double pi = 3.14;
const double *cptr = π //正确
3.const指针
指针和引用不一样,指针是对象,因此可以将指针本身定为常量。常量指针(const pointer)作为一个const类型,必须初始化,而且一旦完成初始化,则它的值(即指向的地址)就无法改变。下面代码初始化了一个指向int的常量指针,const放在curErr前面,说明curErr是个常量。常量指针只是说我一定会指向errNumb而不会发生改变,但是errNumb是可以发生改变的,因为它是个普通int变量。
int errNumb = 0;
int *const curErr = &errNumb;
*errNumb = 0;//正确
但是如果常量指针指向的是常量,那两个都不能发生变化。如下所示errNumb是一个常量,curErr指向errNumb,不能通过*errNumb去改变他的值。
const int errNumb = 0;
int *const curErr = &errNumb;
*errNumb = 0;//错误
4.顶层const
指针本身是不是常量以及指针所指的是不是一个常量,这是两个独立的问题。用名词顶层表示指针本身是一个常量,而名词底层表示指针所指的对象是一个常量。
更一般的,顶层const可以表示任何的对象是常量,而底层const主要用于指针和引用等符合类型。
int i = 0;
int *const p1 = &i; //不能改变p1的值,这是个常量指针,顶层const
const int ci = 42; //单独一个,没有符合类型,本身就是顶层const
const int *p2 = &c1; //指针不是常量,指向的int是常量,指向对象为底层,这是底层const
const int *const p3 = p2; //靠左的是所指对象,是底层const,靠右的是指针,是顶层const
const int &r = ci; //引用的是常量int,都是底层const
执行拷贝操作并不会影响被拷贝对象的值,因此,拷入和拷出的对象是否是const都没什么影响。顶层const不受什么影响,因为它们代表的是自身是否const。
i = ci; //ci是顶层const,对拷贝操作不影响
p2 = p3; //p2和p3都是指向const int,因此可以拷贝。至于p3顶层const不影响。
对于底层const来说,拷贝并不是每次都可接受,它们必须具备相同的底层const资格,即指向的变量必须我相同类型。非常量可以转换常量,反之则不行。通俗来说,就是花心的人可以变成专一的人,但是专一的人,一直得保证是专一的。
int *p = p3; //错误,p3具有底层const,即指向的是const int,但是p没有,不能让非常量转换为const变量
p2 = p3; //正确,p2和p3都是底层const
p2 = &i; //正确,i是普通变量,p2指向的是const变量,普通变量可以转换const变量
int &r = ci; //错误,ci是const变量,不能转换为int普通变量
const int &r2 = i; //正确,i是普通变量,可以转换为const变量
总结:存在指针的变量赋值问题,可以忽略顶层const,要关注底层const,主要就是指针所指向的对象。把const变量转换为普通变量,是不可接受的。把普通变量转换为const变量是可接受的。
const变量好处:
1.给阅读代码的人看到,可以有效理解变量的含义。
2.保护某些变量被无意修改,产生不必要的bug。
《C++ Primer 中文版 》