先简单回忆一下常量的性质:
初始化时:
当用一个对象去初始化另外一个对象,他们是不是const就无关紧要
ci是整形常量,但ci的常量特征仅仅在执行 改变ci 的操作时才会发挥作用
把引用绑定到const对象上,称之为对常量的引用
对常量的引用不能用作修改它所绑定的对象,引用 及其 引用的对象 都是常量
需要注意的是:
因为不允许把ci用作修改它所绑定的对象,所以也不能通过引用去改变ci(假设第四句合法,那我们就可以通过r2去改变ci了,显然是不对的)
以下两句同理
我们口头所说的常量引用其实是对const的引用,严格来说是不存在常量引用的,因为和指针不一样,引用不是对象,我们没有办法让引用本身很定不变
(P.S:由于C++不允许随意改变引用所绑定的对象,所以也可以理解为,所有的引用都是常量,当然了,引用的对象是否是常量,会决定其所能参与的操作,但无论如何也不会影响到引用和对象的绑定关系)
我们知道引用的类型必须要和所引用的对象类型一致,但涉及初始化常量的引用会出现第二种例外(第一种:初始化常量引用是允许用任意表达式作为初始值,只要该表达式能转换成引用的类型)
为什么会出现这种情况?先来看一个简单的例子
运行输出
在这个过程中,其实是编译器把代码改成了:
这种情况下,ri绑定了一个临时量对象,这下你可看懂上面的代码发生了什么了吧
你可以想象以下,如果ri不是常量时,执行了上述初始化过程会带来怎样的后果:如果ri不是常量。就允许对ri赋值,这样就会改变ri所引用对象的值(此时绑定的是临时量而非dval),所以C++也把以下这种行为归为非法
同时注意,对const的引用可能引用一个并非const的对象
对const的引用仅对引用可参与的操作做出了限定,对于引用对象本身是否是一个常量没有做出限定,因此对象也可能是个非常量,允许通过其他途径改变它的值
该程序输出如下:
类似于对常量的引用,指向常量的指针不能用于改变其所指对象的值
同时,想要存放常量对象的地址,只能使用指向常量的指针:
不同于引用,我们能改变指向常量的指针所指向的对象
注意,与引用类似,虽然我们说指针的类型必须与所指对象一致,但是这里有第一种例外:允许一个指向常量的指针指向一个非常量对象
所以,指向常量的指针也没有规定其所指的对象必须是一个常量,所谓指向常量仅仅要求不能通过该指针修改所指向对象的值,而没有规定所指对象的值不能通过其他途径改变
现在我们输出就变成了:
和引用不同,指针本身是对象,所以允许把指针本身定为常量,也就是常量指针,常量指针必须被初始化,并且初始化完成后值(存放在指针对象里的地址)不能改变
把*放const关键字之前,用以说明指针是一个常量(即不变的是指针本身的值)
以下两种写法区别很大:
由于指针本身是一个对象,它又可以指向另外一个对象,因此指针本身是不是常量和指针所指的对象是不是常量就是两个互相独立的问题,顶层const表示指针本身是个常量,底层const表示指针所指的对象是个常量
顶层const其实可以表示任意的对象(自身)是常量,指针式比较特殊的,因为它既可以是顶层也可以是底层const
拷贝操作不会影响被拷贝对象的值,顶层const不受影响
但是底层const就会产生限制:
拷贝操作时,拷入和拷出的对象必须有相同的底层const资格,活着两个对象数据类型能转换(非常量能转成常量,反之不行)