2.1 基础
使用关键字const可以对变量的类型加以限定,将其定义为一个常量
const int buf_size = 512;
任何试图为buf_size赋值的行为都会引发错误
const对象必须初始化
限制:
只能在const类型的对象上执行不改变其内容的操作,例如初始化:
//利用一个对象去初始化另外一个对象,则是不是const都无关紧要
int i = 42;
const int ci = i;
int j = ci;
//上面的代码都是正确的
//ci的常量特征仅在执行改变ci的操作时才发挥作用
默认下const对象仅在文件内有效
如果不使用extern修饰,那么const对象仅在文件内有效,多个文件中出现同名的const变量时,相当于不同文件中定义了独立的不同变量
所以如果想多个文件共享const对象,必须添加extern(定义前)
//file1.c:
extern const int bufsize = fun();
//file1.h:
extern const int bufsize;
//这两个bufsize是同一个
2.2 const的引用
reference to const(对常量的引用)
对常量的引用不能通过引用去修改被绑定的对象
const int ci = 1024;
const int &ri = ci;//正确
r1 = 42;//错误
int &r2 = ci;//错误
引用的类型必须与其所引用对象的类型一致,但是初始化常量引用时允许使用任意表达式,只要能转换成引用的类型
double val = 3.14;
const int &ri = val;
//编译器生成如下代码:
const int temp = val;
const int &ri = temp;
//所以ri绑定的是一个临时量对象
因此当ri不是常量时,我们引用val是 为了通过ri改变val,但是上述的初始化,是绑定临时量,所以在ri不是常量时,这种行为是非法的
引用的对象本身也不必是一个常量,所以允许通过其他途径来改变它的值
int i = 42;
int &r1 = i;
cosnt int & r2 = i;
r1 = 0;//正确
r2 = 0;//错误,r2是常量引用
2.3 指针和const
指向常量的指针
想要存放常量对象的地址,只能使用指向常量的指针,且指向常量的指针不能用于改变其所指的对象的值
const double pi = 3.14;
double *ptr = π//错误,ptr不是指向常量的指针
const double *cptr = π//正确
一般情况下指针的类型必须和其所指的对象一致,但是有例外,其中之一:允许一个指向常量的指针指向一个非常量对象
double dval = 3.14;//dval可以改变,但是不能通过cptr这个指针来改变
cptr = &dval;
const指针
指针是对象,引用不是对象,所以可以将指针本身定义为常量
int e = 0;
int *const cur = &e;//const指针,*放在const前用于说明指针是一个常量
const double pi = 3.14;
const double *const pip = π//首先看double*const pip,代表pip是一个double类型的常量指针,前面加上const ,代表pip是一个指向常量对象的常量指针
注意const pointer,必须初始化,且不能再被改变,不变的是指针本身的值而非指向的值
上面的代码应该从右向左开始读
上面的代码中,cur自己存储的地址不能改变,但是可以通过cur改变e,但是pip自己的地址和指向的对象都无法改变
2.4 顶层const
- 顶层const:用于表示指针本身是个常量
- 底层const:指针所指的对象是一个常量
int i = 0;
int *const pi = &i;//顶
const int ci = 42;//顶
const int *p2 = &ci;//底层
const int *const p3 = p2;//左边顶层,右边底层
const int &r = ci;//用于声明引用的const都是底层const
底层const的拷贝限制:
拷入拷出的对象都必须有相同的底层const资格。或者两对象的数据类型能转换,一般非常量可以转换为常量
int *p = p3;//错误,p没有底层const
p2 = p3;//都是底层const
p2 = &i;//int * 可以转换为const int *
int &r = ci;//错,右边是int常量,左边是普通int&
const int &r2 = i;//正确const int&可以绑定到普通int上