有时我们希望定义一种变量,它的值不能被改变,就要用到关键字const
1.初始化和const
对象的类型决定了其上的操作。const对象必须进行初始化。
2.const引用
可以把引用绑定到const对象上,就像绑定其它对象一样,我们称之为对常量的引用。与普通引用不同之处是常量引用不能改变它所绑定的对象,故在其前加上关键字const。
const int i = 1024;
const int &ri = i; //正确
int &ri1 = i; //错误,试图让一个非常量引用去指向一个常量引用
初始化对const的引用 引用的类型必须与其所引用的对象类型一致,但是有两个例外。第一种情况是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可
int &a = 10; //错误,引用初始值必须是一个对象
double d = 3.14;
int &b = d //错误,此处的初值必须是int类型
int i = 42;
const int &r1 = i; //正确
const int &r2 = 42; //正确
const int &r3 = r1 * 2; //正确r3是一个引用常量
double dval = 3.14;
const int &ri = dval; // 正确ri是一个引用常量
对于上中情况double类型转换为int类型的常量引用,编译器是这样转换的const int temp = dval; //由双精度浮点类型生成一个临时的整形常量
const int &ri = temp //让ri绑定这个临时变量
当然const引用可以引用一个并非const的对象3.指针和const
和引用一样也可以用指针指向常量或非常量。类似于常量引用,指向常量的指针不能用于改变其所指对象的值。要存放常量对象的地址,只能使用指向常量的指针:
const double d = 3.14;
double *pd = &d; //错误
const指针 指针是对象而引用不是,因此允许像其他对象那样,把指针本身定义为常量。常量指针必须初始化,而且一旦初始化完成,它的值就不能在改变
int i = 3.14;
int *const i1 = &i;
4.顶层const
用顶层const表示指针本身是一个常量,用底层const表示指针所指的对象是一个常量。指针类型既可以是顶层const也可以是底层const,这一点和其他类型相比有明显的区别。
int i1 = 1;
int *const i = &i1; //正确,顶层const,没什么影响
int *p = i;
const int *i2 = &i1; //错误,底层const,有影响
5.constexpr和常量表达式
常量表达式是指不会改变并且在编译过程中就能得到计算结果的表达式。显然字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式,一个对象是不是常量表达式由它的数据类型和初始值共同决定。
const int max_files = 20; //是常量表达式
const int limit = max_files + 1; //是常量表达式
int staff_size = 27; //不是常量表达式
constexpr变量 在c++11标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
字面值类型
常量表达式的值需要在编译时就得到计算,因此对声明constexpr时用到的类型必须有所限制。因为这些类型一般比较简单,值也显而易见、容易得到,就把它们称为“字面值类型”
指针和constexpr
const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针