const限定符
因为使用const限定符声明的变量就是常量,是不可以被修改的,所以在声明时必须进行初始化的。编译器在编译时,会将const常量替换为对应的常量值。
默认情况下,const限定的变量的作用域被设定为文件作用域。但是在某些时候,我们想多个文件共享const变量时,解决办法就是:对于const变量不管是声明还是定义都添加extern关键字。
对const的引用
对const引用的特性
和普通引用不同,对const的引用 不能被用作媒介去修改它所绑定的变量。
const int num = 1;
const int &num_quote = num; //正确:引用及其对应的对象都是常量
num_quote = 12; //错误:num_quote是对常量的引用
int &num_quote1 = num; //错误:试图让一个非常量引用指向一个常量对象
对const引用初始化问题
c++中,引用的类型必须和其所引用的对象的类型一致,但是有两个例外,第一个例外就是在初始化常量引用时,允许用任意表达式作为初始值。
对const引用的本质解释
double dval = 3.14;
const int & ri = dval; //允许const的引用的类型和其对象的类型不同
其实绑定在ri上的对象还是一个int型,而不是double型的数据,因为上述代码在编译器变成如下形式:
cosnt int temp=dval;
cosnt int & ri=temp;
在这种情况下,ri绑定了一个临时量。临时量就是当编译器需要一个空间来暂存表达式求值结果时临时创建的一个未命名的变量。因为我们规定const引用是不可以修改它绑定的那个对象的值的,所以其实就是我们不准去修改那个临时量,这也就是为什么const的引用可以使用任何表达式作为初始值。
指针和const
指向常量的指针不能用于改变过其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针。
const double pi = 3.14;
double * ptr = π //错误:ptr是一个普通指针
const double * ptr1 = π //正确:ptr1可以指向一个常量
*ptr1 = 43; //错误:不能给*ptr1赋值
const指针
因为指针是一个对象,所以也可以把指针本身定义为常量,常量指针必须初始化(和其他常量是一样的),而且一旦被初始化,它的值(存放在指针中的地址)就不能改变。常量指针不变的是指针自己的值,而不是其对象的值
int num = 0;
int * const num_pointer = # //num_pointer一直指向num,
const int num1=2;
const int * const num1_pointer=&num1; //num1_pointer是指向常量对象的常量指针,也不允许通过num1_pointer去改变num1 的值
顶层const
名词顶层const表示指针本身是一个常量,而用名词底层const表示指针所指的对象是一个常量。顶层const可以表示任意的对象,用于声明引用的const都是底层const
const int ci = 2; // ci不变,为顶层const
const int& r = ci; // 用于声明引用的都是底层const
const int* const p3 = &ci // 靠右的const是顶层const, 靠左的是底层const
拷贝数据的差异
- 顶层const 不用考虑拷入拷出的对象的类型问题
- 底层const 拷入和拷出对象必须具有相同的底层const资格, 或者两个对象必须可以互相转换。一般来说, 非常量可以转换为常量,反之不行。
constexpr和常量表达式
将变量声明为constexpr 类型方便由编译器来验证变量值是否是一个常量。如果你认定变量时一个常量表达式, 那么就把它声明为 constexpr类型。
constexpr int mf = 20; // 20 是一个常量表达式
constexpr int* p= &mf; // 此时是常量指针,而不是指向整型常量mf的指针。
constexpr把它所定义的对象置为了顶层const。