关于顶层和底层的const的区别
举例说明
int i = 0;
int *const p1 = &i; // p1变量本身是一个指针常量,不能被修改,所以这个const是一个顶层const
const int j = 0; // j变量本身是一个整型常量,不能被修改,所以这个const也是一个顶层const
const int *p2 = &j; // p2可以被修改,所以这个const不是顶层const,*p2不能被修改,所以它是一个底层const
const int *const p3 = p2; // p3和*p3都是常量,那么右边的const是一个顶层const,左边的const则是一个低层const
const int &r= j; // r是一个整型常量引用,所以这个const是一个底层const,即用于声明引用的const都是底层const
那么执行对象的拷贝动作时,对底层const影响较大,对顶层const不受什么影响。
i = j; // 正确拷贝了j的值,j是一个顶层const,个人觉得正确的原因是因为,如果j是个整型常量,赋值给另一个非常量是不会有安全问题的。
p2 = p3; // 正确拷贝,底层const p3赋值给了底层const p2,顶层const p3不受影响,原因同上,
// 但是我们反过来看底层const为什么也没问题呢,个人理解原因是*p2不可修改,这样的话即使p3赋值给了p2,也不会修改*p3,不会影响p3
我们来看一些反例:
int *p = p3; // 错误:直观上看p3有底层const,p什么也不是,所以不具备相同底层const的两个变量赋值是会有问题的
// 但是从背后的影响角度上个看,我个人觉得是因为*p是可以修改的,但是*p3不可修改,明显的冲突了
p2 = &i; // 正确:p2是底层const,i什么也不是,官方解释int*能转成const int *,是可以赋值给p2的
// 不过我建议还是从背后影响来看比较合理,任何对p2的操作影响i的值都是可以的
int &r = j ; // 错误,与底层const无关,所以说嘛,从深层次的角度看,j不可以修改,而通过r来修改j的值是不行的,所以非法
const int &r2 = i; // 正确,i只是个普通常量,但是由于r2是常量引用,可以被赋值,如果是非const则不可以
其他情况
另外说到使用auto的时候,会忽略顶层const,同时底层const会留下来,例如:
int i = 0;
const int ci = i, &cr = ci;
auto a = ci; // ci 是顶层const被忽略掉,所以auto a 等价于int a;
// 但其实我们来做个假设,如果保留了顶层const,那么auto a就等价于const int a看起来问题也不大,但是这样的话感觉缺失了灵活性,
// 因为int a更灵活,可以修改a的值,所以感觉为什么官方需要在auto a 加上const才表示要转成const,这样比较灵活一些。
auto b = &ci; //ci的值不可以修改,是一个底层const,所以b也是底层const,等价于 const int *b