const对象一旦创建后其值就不能再改变,所以const对象必须初始化。
**初始化和const**
如果利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要。
**默认状态下,const对象仅在文件内有效**
如果想在多个文件之间共享const对象,必须在变量的定义前添加extern关键字。
1.const的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。对常量的引用
不能被用作修改它所绑定的对象:
const int ci =1024;
const int &r1 = ci; //正确:引用及其对应的对象都是常量
r1 = 42; //错误:r1是对常量的引用
int &r2 = ci; //错误:试图让一个非常量引用指向一个常量对象
**初始化和对const的引用**
引用的类型必须与其所引用对象的类型一致,有例外:初始化常量引用时,允许用任意表达式作为初始值,
只要该表达式的结果能转换成引用的类型即可(即初始化常量引用,可以用表达式及其他任意形式,但其结果能转
换成引用的类型就可以)。
**对const的引用可能引用一个并非const的对象**:常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身
是不是一个常量未做限定。
2.指针和const
指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针。
**const指针**
常量指针必须初始化,而且一旦初始化完成,则它的值(即存放在指针中的地址)就不能再改变。
把*放在关键字const之前,说明指针是一个常量,即不变的是指针本身的值而不是指向的那个值。
int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb
const double pi = 3.14159;
const double *const pip = π //pip是一个指向常量对象的常量指针
弄清楚这些声明,最有效的方法是从右向左阅读。以最后一句为例,const说明pip是常量对象,带*说明其为常量
指针,double说明该指针指向的对象为双精度,const说明该指针指向的对象为双精度常量,因此pip为指向双精度常量
的常量指针。
指针本身是一个常量,并不意味着不能通过指针修改其所指对象的值,能否这样做完全依赖于所指对象的类型。
例如:pip是一个指向常量的常量指针,则无论是pip所指的对象值,还是pip自己存储的那个地址都是不能改变的。
相反的,curErr指向的是一个一般的非常量整数,那么就完全可以用curErr去修改errNumb的值。
*pip = 2.72; //错误:pip是一个指向常量的指针
//如果curErr所指的对象(也就是errNumb)的值不为0
if (*curErr) {
errorHandler ();
*curErr = 0; //正确:把curErr所指的对象的值
}
3.顶层const
**顶层const**: 顶层const表示指针本身是一个常量,底层const表示指针指向的对象是一个常量。
int i =0;
int *const p1 = &i; //不能改变p1的值,这是一个顶层const
const int ci =42 ; //不能改变ci的值,这是一个顶层const
cosnt int *p2 = &ci; //允许改变p2的值,这是一个底层const
const int *const p3 = p2; //靠右的const是顶层const,靠左的是底层const
const int &r = ci; //用于声明引用的const都是底层const
当执行对象的拷贝操作时,顶层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上
4.常量表达式和constexpr
常量表达式是指值不会改变并且在编译过程中能得到计算结果的表达式。一个对象(或者表达式)是不是常量表达式由
它的数据类型和初始值共同决定的。
**constexpr**
一般来说,如果你认定变量是一个常量表达式,那就把它声明成constexpr类型。
**字面值类型**
常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制,比如:算术类型、引用
和指针等,此职位字面值类型。
**指针和constexpr**
在constexpr声明中,如果定义了一个指针,限定符constexpr对指针有效,与指针所指的对象无关:
const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针(const把它所定义的对象置为了顶层const)
与其他常量指针类似,cosntexpr指针既可以指向常量也可以指向非常量:
constexpr int *np = nullptr; //np是一个指向整数的常量指针,其值为空
int j = 0;
constexpr int i =42; //i的类型为整形常量
//i和j都必须定义在函数体之外
constexpr const int *p = &i; //p是常量指针,指向整型常量i
constexpr int *p1 = &j; //p1是常量指针,指向整数j