这是个好东西,Effective C++里都已说过:能用的地方尽量用,大师都这样说了,我们这些渣渣为何不遵循?
const就是常量,这就有个重要的东西了:常量必须初始化
const int a = 0;
const int b = get_size(); //已知有get_size()函数
const int c; //错误!!!
---------------------------------------------------------------------------------------------------------------
int m = 42;
const int n = m;
---------------------------------------------------------------------------------------------------------------
对const对象的任何修改都会导致错误。
const a = 0;
a = 1; //错误!!
==============================分割线==============================
默认状态下,const对象仅在文件内有效
当定义一个const对象时,编译器会在编译过程(#define是在预处理阶段)中将用到该变量的地方都替换成对应的值。
为了执行这个替换,编译器必须知道变量的初始值,如果有多个文件,每个文件都得定义这个变量。当多个文件中出现同名的const变量时,其实等同于在不同的文件中分别定义了独立的变量。如果想在一个文件中定义了,在其他文件中使用,可以用关键字extern。
extern const int a = 0; //文件1.cpp中定义并初始化了一个常量,能被其他文件访问
extern const int a; //在2.cpp中,与1.cpp是一个常量
==============================分割线==============================
初始化和对const的引用,const引用可以绑定到一个并非const对象上
int i = 0;
const int &r1 = i; //允许将const int&绑定到一个普通int对象上
const int &r2 = 42; //正确
const int &r3 = r1 * 2; //正确
int &r4 = r1 * 2; //错误,r4是普通引用
具体原因见C++primer P55
==============================分割线==============================
指针和const:
主要是两种:
1、指向常量的指针:意思是指针指向的那个对象时常量,不可以改变,但是指针本身可以改变指向的对象
const int num = 0;
int *ptr1 = # //错误,ptr1是普通指针
const int *ptr2 = # //正确,ptr2是一个指针常量的指针
const int num1 = 1;
ptr2 = &num1; //正确
2、常量指针:必须初始化,是指针本身就是常量,也就是指针不能改变它指向的位置,但是指针所指的对象可以改变值
int num = 0;
int *const ptr = # //ptr将一直指向num的地址,不能改变
num = 1; //正确,可以改变num
int num1 = 1;
ptr = &num1; //错误,不能改变ptr指向的地址
其实很简单,分辨方法,如果const在*左边那么,物为常量;const在*右边,指针为常量
---------------------------------------------------------------------------------------------------------------
顶层const:任意对象本身是常量
底层const:指针所指的对象是一个常量,与复合类型有关
执行拷贝操作时:顶层const不受影响,底层const拷入或者拷出的对象必须具有相同的底层const资格,或者两个对象的数据类型必须能够转换
==============================分割线==============================
constexpr和常量表达式
1、常量表达式:指不会改变并且在编译过程就能得到计算结果的表达式,因此,字面值属于常量表达式,用于常量表达式初始化的const对象也是常量表达式。
const int num = 0; //num是常量表达式
const int num1 = num + 1; //num1是常量表达式
int num3 = 0; //num3不是常量表达式
const int temp = get_size(); //temp不是常量表达式,因为结果需要在运行时才能获取
2、constexpr变量
在一个复杂系统中,很难分辨一个初始值到底是不是常量表达式。C++11新标准中,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
constexpr int num0 = 1; //1是常量表达式
constexpr int num1 = num0 + 1; //num0 + 1是常量表达式
constexpr int sz = size(); //只有当size是一个constexpr函数时才能声明成功
3、字面值类型
一个类型简单、值显而易见、容易得到,在编译时就能得到,就为字面值类型
算术类型,引用,指针都属于字面值类型。自定义类,IO库,string类型都不属于字面值类型,也就不能定义为constexpr。
4.指针和constexpr
如果constexpr声明中定义了一个指针,那么constexpr只对指针有效,与指针所指的对象无关
const int *ptr1 = nullptr; //ptr1是一个指向整数型常量的指针
constexpr int *ptr2 = nullptr; //ptr2是一个指向整数的常量指针
两者区别见const指针