C++primer 2.4 const限定符
使用关键字const对变量类型加以限定,其值不可被改变。因为值不可被改变,所以const对象必须初始化。
如:const int bufSize=512;
初始化和const
Const类型的对象除了不可改变值外,其它操作与非const类型类似。在初始化时,利用一个对象去初始化另一个对象,则它们是不是const都无关紧要。
默认状态下,const对象仅在文件内有效
在不同文件中,即使定义的对象名字相同,但其实是定义的不同变量。想要在多个文件中使用同一const对象,前面加extern。
2.4.1 const引用
可以把引用绑定到const对象上,我们称之为对常量的引用。对常量的引用不能被用作修改它所绑定的对象。引用的类型与其所引用对象的类型一直,但有两个例外。第一种例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式:
当一个常量引用被绑定到另外一种类型上时到底发生了什么:
如:
double dval=3.14;
cons tint &ri=dval;
编译器会把上述代码变成如下形式:
cons int temp =dval;
const int &ri=temp;
ri绑定了一个临时量对象。所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。如果ri不是常量,为非法。
对const的引用可能引用一个并非const的对象
常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未做限定。
2.4.2 指针和const
与引用一样,也可以令指针指向常量或非常量。类似于常量引用,指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针,指针类型必须与其所指对象的类型一致,但是有两个例外:允许一个指向常量的指针指向一个非常量对象;
const指针
指针是对象而引用不是,常量指针必须初始化,而且一旦初始化完成,则它的值就不能再改变了。
2.4.3 顶层const
用名词顶层表示指针本身是个常量,而用名词底层表示指针所指的对象时一个常量。
更一般的,顶层const可以表示任意的对象时常量,这一点对任何数据类型都适用,如算术类型、类、指针等。底层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 int *const p3=p2; //靠右的const是顶层const,靠左的是底层const
const int &i=ci; //用于声明引用的const都是底层const
当执行对象的拷贝操作时,常量是顶层const还是底层const区别明显。其中,顶层const不受什么影响:
i=ci; //正确,拷贝ci的值,ci是一个顶层const,对此操作无影响
p2=p3; //正确:p2和p3指向的对象类型相同,p3顶层const的部分不影响
另一方面,底层const的限制却不能忽视。当执行对象的拷贝操作时,拷入和拷出的对象必须具有相同的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上去
p3既是顶层const,也是底层const,拷贝p3时,可以不在乎它是一个顶层const,但是必须清楚它指向的对象得是一个常量。因此,不能用p3去初始化p,因为p指向的是一个普通的(非常量)整数。另一方面,p3的值可以赋给p2,是因为这两个指针都是底层const,尽管p3同时也是一个常量指针(顶层const),仅就这次赋值而言不会有什么影响。
2.4.4constexper and Constant Expressions
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。
Constexpr变量
声明为constexpr类型的变量一定是一个常量,而且必须用常量表达式初始化:
Constexpr int mf=20;
Constexpr int Limit=mf+1;
Constexpr int sz=Size(); //只有当size是一个constexpr函数时才是一条正确的声明语句。
目前接触过的数据类型为止,算术类型。引用和指针都属于字面值类型。自定义类、IO库、string类型则不属于字面值类型,也就不能被定义成constexpr。
一个constexpr指针的初始值必须是nullptr或者0;或者是存储于某个固定地址中的对象。
指针和constexpr
在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指对象无关。