C++ 11—const用法
有时我们希望定义一个这样的变量,它的值不能被改变。例如,用一个变量来表示缓冲区的大小。使用变量的好处是当我们觉得缓冲区大小不再适合时,很容易对其进行调整。(直接改变const定义的值即可)为了实现这一要求,可以用关键字const对变量加以限定。
const int buffSize = 512; //输入缓冲区的大小
这样buffSize就定义成为一个常量。任何试图为buffSize赋值的行为都会引发错误:
buffSize = 512; //错误,试图向const对象写值
因为const对象一旦创建后其值就不能再改变,所以cosnt对象必须初始化。
-
其实const主要限定就是只能在const类型对象上执行不改变其内容的操作
-
默认状态下,const对象仅在文件内有效(当多个文件中出现同名的const变量时,其实等同于在不同文件中分别定义了独立的变量)//解决办法:对于const变量不管是声明还是定义都添加extern关键字
一、const引用
引用也可以绑定到cosnt对象上,就像绑定到其他对象上一样,这称为对常量的引用。与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。
const int ci = 1024;
const int &r1 = ci; //正确:引用及其对应的对象都是常量
r1 = 42; //错误:r1是对常量的引用,不能在对其进行赋值(改变常量的操作)
int &r2 = ci; //错误:试图让一个非常量引用ci常量对象
- 初始化和对const的引用
引用的类型必须与其所引用对象的类型一致,但是有例外:-
初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转化成引用的类型即可。尤其允许为一个常量引用绑定非常量对象、字面值、甚至是一个一般表达式。
举个栗子:const 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是一个普通的非常量引用,而r1是一个常量引用
-
Why Wrong?
举个栗子来解释:
double dval = 3.14;
const int &ri = dval;
此处ri引用了一个int型的数,对ri的操作应该是整数运算,但dval却是一个双精度浮点数而非整数。因此为了确保让ri绑定一个整数,编译器把上述代码变成如下形式:
const int temp = dval; //由双精度浮点数生成一个临时的整形常量,即3;
cosnt int &ri = temp; //让ri绑定这个临时变量
在这种情况下,ri绑定了一个临时量(temporary)对象。所谓的临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。
二、const与指针的故事
与引用一样,也可以让指针指向常量或非常量。类似于常量引用,指向常量的指针(pointer to const)不能用于改变其所指向的对象的值。要想存放常量对象的地址,只能使用指向常量的指针:
const double pi = 3.14; //pi是个常量,它的值不能改变
double *ptr = π //错误:ptr是一个普通指针
const double *cptr = π //正确:cptr可以指向一个双精度常量
*ptr = 42; //错误:不能给*cptr赋值
指针的类型必须与其所指向的对象类型一致,但是有两个例外。第一种例外情况是允许令一个指向常量的指针指向一个非常量对象。
double dval = 3.14; //dval是一个双精度浮点数,它的值可以改变
cptr = &dval; //正确:但是不能通过cptr改变dval的值
和常量引用一样,指向常量的指针也没有规定其所指向的对象必须是一个常量。所谓指向常量的指针仅仅要求不能通过该指针来改变所指向的对象的值(其实还是可以通过其他方式改变被指向对象的值)。
const指针
指针是对象而引用不是,因此就像其他对象类型一样,允许把指针本身定义为常量,即为常量指针。指针常量必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。
int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb
const double pi = 3.14159;
const double *const pip = π //pip是一个指向常量的常量指针
错误的栗子:
*pip = 2.72; //错误:pip是一个指向常量的常量指针(错在指向常量就不能再向常量赋值)
if(*curErr) { //如果curErr所指向的对象(也就是errNumb)的值不为零
errorHandler();
*curErr = 0; //正确:把curErr所指向的对象的值重置(curErr本身保存的地址不能改变,curErr是常量指针)
}
三、顶层const
如前所述,指针本身是一个对象,他又可以指向另外一个对象。因此,指针本身是不是常量以及指针所指的是不是一个常量就是俩个相互独立的问题。用名词顶层const(top-level const)表示指针本身是一个常量,而用名词底层cosnt(low-level const)表示指针所知的对象是一个常量。