1、初始化
const对象一旦创建后的其值就不能改变,所以const对象必须初始化。
初始值可以是任意地复杂表达式:
const int i = get_size(); // 正确:运行时初始化
const int j= 42; //正确,编译时初始化
const int k; //错误:k是一个未经初始化得值
如果用一个对象去初始化另一个对象,则这个对象是不是const都没关系:
int i = 42;
const int ci= i; //正确:i的值被拷贝给了ci
const j = ci; //正确:ci的值被拷贝给了j
2、const的引用
可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。与普通引用不同是的,对常量的引用不能被用作修改它所绑定的对象。
const int ci = 42;
const int &r1 = ci; //正确:引用及其对应的对象都是常量
r1= 42; //错误:r1是对常量的引用,不能修改
int &r2 = ci; // 错误:试图让一个非常量引用指向一个常量对象
初始化和对const的引用
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是一个普通的个非常量引用
不能通过改变r1的值来改变i的值,但可以通过改变i的值来改变r1的值。
3、指针和const
指针和常量结合在一起可以组合成指针常量、常量指针以及指向常量的指针常量(前两者的结合)。结合在一起到底是哪一个可以从常量符号const和指针符号*的先后顺序来判断。const在*前则是常量指针,如果*在const之前则是指针常量。
const(*号)左边放,我是指针变量指向常量;
const(*号)右边放,我是指针常量指向变量;
const(*号)两边放,我是指针常量指向常量;
(1)指针常量
int i = 0;
int * const j = &i;
指针 常量
指针常量指的是指向的指针(地址)是常量,指针本身不能改变,指针指向的值可以改变。用名词顶层const表示指针本身是个常量。
(2)常量指针
int i = 0;
int const * j = &i;
常量 指针
常量指针指的是指针指向的值(对象)不可改变,但指针的值可以改变。用名词底层const表示指针所指的对象是一个常量。
常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化const对象也是常量表达式。
一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定,例如:
const int max_files = 20; // 是
const int limit = max_files + 1; // 是
int staff_size =27; //不是
const int sz = get_size(); // sz不是常量表达式,因为要在运行时才能得到具体值
在一个复杂的系统中,很难分辨一个初始值到底是不是常量表达式。当然可以定义一个const变量并把它初始值设为我们认为的某个常量表达式,但实际使用时,尽管要求如此却常常发现初始值并非常量表达式的情况。
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量是不是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量个表达式初始化:
constexpr int mf=20; // 20是一个常量表达式
constexpr int limit = mf + 1; // mf+1是一个常量表达式
constexpr int sz = size(); // 只有当size是一个constexpr函数时才是一条正确的声明语句
5、指针和constexpr
在constexpr声明中如果定义了一个指针,限定符constexpr仅仅对指针有效(变成顶层const),与指针所指的对象无关:
const int *p= nullptr; // p是一个指向整型常量的指针,常量指针,底层const
constexpr int *q = nullptr; // q是一个指向整数的常量指针,指针常量,顶层const