const的引用
说const引用之前需要说明,这是建立在引用的前提下,如果是普通的拷贝赋值就基本不需要使用到const(有关权限)。
1 权限不能放大(可平移、缩小)
如何解释权限不能放大? 阅读下面的代码
可以看到:
a是const int 类型,是只读的。
b是int类型,是可读可写的,要绑定a(意味着b想修改自己的时候会将a一起修改,但是我们知道,a是只读的,不能修改),会出错。
什么是权限的放大?
只读 --> 可读可写
权限不能放大,但是可以平移,所以下面的代码就是正确的。
什么是权限的平移?
只读 ---> 只读
可读可写 --> 可读可写
如果是权限的缩小,代码也可以通过
什么是权限的缩小?
可读可写 ---> 只读
如果是拷贝,就没有权限的概念!!!
b是a的拷贝,b的改变不会影响到a,所以就算a是只读的,b是可读可写的,也不会有问题。
根本的原因就是:b是a的拷贝,b的改变不会影响到a.
1.1 临时对象具有常性
临时对象具有常属性,本文谈及两个方面:
1.类型转换
2.函数创建栈帧返回的临时变量
1.1.1 隐式类型转换
为什么类型转换会产生临时变量?
上面的代码,a是int类型,b是double类型。
当运算符两边的变量类型不同时,会发生类型提升(提升有自己的规则,感兴趣的可以搜一下,本文这个不是重点,所以不讲)
a是int类型,占4个字节
b是double类型,占8个字节
当比较的时候,发生提升。不是直接将a的值发生改变,是创建一个新的临时变量,将临时变量提升为8个字节的double类型,将临时变量和值和b进行比较。
既然当运算符两边的变量类型不同时,会发生类型提升。那么,赋值运算符也属于其中,所以也会发生提升,也会产生临时变量 --> 临时变量具有常性。
上面的代码编译会出错,为什么呢?
因为a是int类型,将int类型转化为double类型,会产生临时变量,临时变量具有常性。将const double类型变量转化double类型,是权限的放大!所以会出错。
而如果将b前面加上const,就能编译通过:
临时变量具有常性,是const double类型,而b是const double类型。这是权限的平移。
1.1.2 函数传值返回是临时变量
1.2 const引用做函数形参
什么时候会给函数传参用引用?
当传递的内容空间占用比较大的时候,因为如果是传值传参,就是拷贝一份;而如果是传引用,就是传别名,就是拷贝,效率就会提高。
上面的代码为什么会出错?
因为传递形参的类型是string类型,而"hella"和"hello"是const string类型,这属于权限的放大! 、
改进的方式有两个:
1.将引用去除,直接传递拷贝。 因为拷贝不涉及权限问题
2.加上const,实现权限的平移。
结论:当定义函数形参的时候,如果确定这个函数不会修改实参的内容,就应使用const&。
这样做的好处:
1.传递引用可以减少拷贝,提高效率
2.使用const引用,既可以传递const类型的变量,也可以传递非const类型的变量。而使用非const引用,就只能传递非const引用。
2 const指针
小技巧:从右往左读,看const离谁近!
第一个p1中:const离p1近(离指针近) 代表不能修改的值是指针本身,本例中是p1。
因为指针本身不能修改,所以p1只能一直指向a(p1的指向不能改变)。但是*p1是可以改变的。
p1的指向不能改变!
但是p1所指向的变量的内容是可以改变的!
第二个p2中:const离*近(离*p2近,就是解引用)代表不能修改的值是指针解引用,也就是指针所指向的值。
不能修改*p2的值!
p2的值可以变,也就是说,p2可以改变指向!
总结:
1. int* const p1表示指针本身是一个常量 - - - - 因为const修饰的是指针
2. const int* p2表示指针所指向的对象是常量 - - - - 因为const修饰的是指针的解引用
2.1 顶层const
顶层const(top-level const) 表示指针本身是个常量
我们可以理解为:顶层const ---> const离p近
2.2 底层const
底层cosnt(low-level const)表示指针所指向的对象是常量
我们可以理解为:顶层const ---> const离*p近
为什么第一个不能通过编译?
因为p1是底层const,
*p1的值不能改变,而int* p2是int*类型,可以改变p2所指向的内容,属于权限的放大!
为什么第二个可以通过编译?
因为p3是顶层const,
不能改变的是指针本身,指针所指向的内容是可以改变的。
p4是int*类型,可以改变指针所指向的内容,属于权限的平移!
const修饰this指针
使用const修饰this指针的时候,将成员函数变成常成员函数了。
意义:方式程序员不小心修改数据成员的值!