初始化和const
const
对象一旦创建后其值就不能被改变,所以 const
对象必须初始化。
默认状态下, const
对象仅在文件内有效。
- 当在多个文件中出现了同名的
const
变量时,其实等同于在不同的文件中分别定义了独立的变量。 - 如果想在多个文件中共享
const
变量,在声明和定义const
变量时加上extern
关键字。
const的引用
引用的类型通常必须与其所绑定的对象类型一致,但是有两个例外,第一种就是在初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的结果能够转换成引用的类型即可。尤其是为常量引用绑定一个非常量对象、字面值甚至是一般表达式。
int i = 42;
const int &r1 = i; //正确,允许常量引用绑定到一个普通对象上
const int &r2 = 42; //正确,允许常量引用绑定到字面值
const int &r3 = r1*2; //正确,r3是一个常量引用
int &r4 = r1*2; //错误,r4是一个普通引用,不能绑定到表达式
对const的引用可能引用一个非const的对象。
int i = 42;
int &r1 = i;
const &r2 = i;
r1 = 0; //正确,r1并非常量
r2 = 0; //错误,r2是常量引用
指针与const
指向常量的指针不能用于改变其所指向对象的值,要想存放常量对象的地址,只能使用指向常量的指针。
const double pi = 3.14;
double *ptr = π //错误,ptr是一个普通指针
const double *cptr = π //正确,cptr可以指向一个双精度常量
const指针
指针是对象,因此可以把指针本身定义成常量,常量指针必须初始化,并且一旦初始化完成,则它的值就不能改变。
int errnum = 0 ;
int * const curErr = &errnum; //curErr将一直指向errnum
顶层const
指针本身是不是常量与指针所指向的对象是不是常量是两个独立的问题,用顶层const表示指针本身是常量,而用底层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 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& 不能绑定到const int
const int r2 = i; //正确,const int 可以绑定到一个int上
constexpr和常量表达式
- 常量表达式是指值不会改变并且在编译过程中就能计算结果的表达式。
- 字面值属于常量表达式。
- 用常量表达式初始化的const对象也是常量表达式。
- 一个对象或者表达式是否是常量表达式由数据类型和初始值共同决定。
const int max_files = 20; //mex_filex是常量表达式
const int limit = max_files + 1; //limit是常量表达式
int staff_size = 27; //staff_size不是常量表达式,27虽然是字面值,但是其数据类型是int
const int sz = get_size(); //sz不是常量表达式,虽然数据类型是const int 但是具体值只有运行时才知道
constexpr变量
在一个复杂系统中,很难分辨初始值是不是一个常量表达式。C++11新标准规定,允许将变量声明为 constexpr
的类型以便由编译器来验证变量的值是不是一个常量表达式。
声明成 constexpr
的变量一定是常量,而且必须用常量表达式初始化。
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = size(); //只有当size是一个constexpr函数时,声明才正确
普通函数不能作为 constexpr
变量的初始值,新标准规定了一种特殊的 constexpr
函数,这种函数能够在编译时得到其计算结果,可以使用 constexpr
函数初始化 constexpr
变量。
指针和constexpr
在 constexpr
声明中如果定义了一个指针,限定符 constexpr
仅对指针有效,与指针指向的对象无关。
const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针