庖丁解牛<c++primer>系列二:const关键字

来源:互联网 发布:软件危机的例子 编辑:程序博客网 时间:2024/06/06 01:20

转载请注明出处
-const关键字的定义
如果我们定义一个变量,但是在以后的维护中不想改变里面的值,就可以用const关键字对变量的类型进行锁定。正由于一旦赋值后就不能对其进行改变,所以const必须初始化。

-初始化时候注意事项
由于const必须定义的时候必须初始化,而且const关键字仅在文件内有效。因为担心重复定义问题,所以仅在文件内有效,而在其它文件中通过声明来使用它。

如果想在多个文件中共享const对象,必须通过添加关键字extern来实现的。

//file_1.cpp 定义并初始化了一个常量,该常量能被其它文件访问extern const int bufSize = fcn();//file_1.h头文件extern const int bufSize; //与file_1.cpp中定义的bufSize是同一个

refernce to const(对常量的引用):把引用绑定到const对象上面,但是和普通引用的区别是,对常量的引用不能被用作修改它所绑定的对象。因此对const的引用可以简称常量引用。

const int ci=1024;const int &r1=ci; //正确,引用及其对应的对象都是常量r1=42; //错误,r1是对应常量的引用int &r2=ci; //错误,让一个非常量引用指向常量的对象,正确的处理方法就是前面加constint i=42;const int &r3=i; //正确,允许将const int &绑定到一个普通的int对象上

临时量对象:简称临时量,指当编译器需要一个空间来暂时存储表达式的求值结果时临时创建一个未命名对象。

double a=3.14;const int &i=a; //const int &i=a 是由 const int temp=a; const int &i=temp 这两步构成的
int i=42;int &r1=i; //引用(改名)r1绑定对象iconst int &r2=i; //r2也绑定i,但是不允许通过r2改变i的值r1=0; //r1不是常量,因此i值是0r2=0; //错误,r2是一个常量,不能改变

指针和const
指向常量的指针(pointer to const):要想存放常量对象的地址,只能使用指向常量的指针,但是不能用于改变其所指对象的值。

const double pi=3.14; //pi是一个常量,值不能改变const double *c=&pi; //c指向一个双精度常量double *p=&pi; //错误,p是一个普通指针,不能指向一个常量*c=42; //错误,常量不能赋值double dval=3.14;c=&dval; //允许一个指向常量的指针指向非常量对象

常量指针(const pointer):必须初始化,而且一旦初始化完成,它的值就不能改变了。

int a=0;int *const b=&a; //b一直指向a,不能改变const double pi=3.14;const double *const ppi=&pi; //ppi是一个指向常量的常量指针,有点绕口吧ヽ(✿゚▽゚)ノ

顶层const(top-level const)和底层const(lou-level const):由于指针本身是一个对象,它又可以指向另外一个对象,因此我们把指针本身的常量用顶层const表示,我们把指向对象的常量用底层const表示。

int a=0;int *const b1=&a; //不改变b1的值,顶层constconst int c=42; //不改变c的值,顶层constconst int *b2=&c; //改变b2的值,低层constconst int *const b3=b2; //右边是顶层const,左边是低层constconst int &r=c; //声明引用都是低层constint *b=b3; //错误,由于b3是底层constb2=b3; //正确,b2和b3都是底层constb2=&i; //这是本节的难点,大家记住这个正确的原因是非常量可以转化为常量,但是反之不成立int &r=c; //普通int&不能绑定到int上const int &r2=i; //const int&可以绑定到int上

部分童鞋对上面代码感觉困惑原因是对底层const执行拷贝操作时候,拷贝和被拷贝的对象必须具有相同的底层const,或者两者具有可以互相转换的数据类型。

和常量表达式
常量表达式(const expression)指值不会改变并且在编译过程中就能得到计算结果的表达式。一个对象或者表达式是不是常量表达式由它的数据类型和初始值共同决定的。

const int max_files=20; //max_files是常量表达式const int limit=max_files+1; //limit是常量表达式int staff_size=27; //因为staff_size类型不是const int所以不是常量表达式const int sz=get+size(); //虽然sz是常量,但是它的值等到运行时候才能够获取,也不是常量表达式

constexpr变量
“C++11”新标准规定,声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。所以如果在编写代码时候你认定某个变量是一个常量表达式,那最好就把它声明为一个constexpr类型。

constexpr int mf=20; //20是一个常量表达式constexpr int limit=mf+1; //mf+1是一个常量表达式constexpr int sz=size(); //只有当size函数是一个constexpr函数时,才是一条正确的声明语句,否则都不是正确的声明

字面值类型(literal type):声明constexpr时用到的类型成为字面值类型,经常接触的字面值类型有算术类型、引用和指针等。
注意:
1、函数体内定义的变量不能用来初始化constexpr,函数体外的对象可以用来初始化conseexpr指针。
2、在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关。

const int *p=nullptr; //p是一个指向"整形常量"的指针constexpr int *q=nullpter; //q是一个“常量指针”
0 0