顶层const和底层const
什么是 顶层const
和 底层const
顶层const
:表示指针是一个常量。
底层const
:表示指针所指向的对象是一个常量。
1、例子
指针中const
const int *const p = new int(10);
第一个const是底层const ,第二个是顶层const。
普通变量中const
const int a = 10;
int const b = 10;
因为是普通变量所以不区分顶层或是底层const,不论const的位置在哪,都声明了这个变量不允许被修改。
引用中的const
const int ci = 10;
const int& c = ci;
用于声明引用的const都为底层const
2、原因
当执行对象的拷贝操作时,常量是顶层const还是底层const的区别明显。其中顶层const可以忽略,但是底层const不能忽略。
我们进行分析:
const int *const p = new int(10);
int *p1 = p;
int *const p2 = p;
const int *p3 = p;
如下所示,我们忽略所有的顶层const:
const int* p = new int(10);
int *p1 = p; //error:类型不一致
int *p2 = p; //error:类型不一致
const int *p3 = p; //right:变量类型一致
其次我们继续观察:
const int* p = new int(10);
int *p1 = p; //error
此处我们未修饰p的指向,但是使用了const修饰了p的值。
如果第二句可以执行,我们可以接着执行这一句 * p1 = 10。那么 p的值也会发生改变,这和我们开始约定的 const int* p出现了冲突,所以出现错误。
还有一个容易出现的误区:
const int a = 10;
int *p4 = &a; //error
这里 &a存放的是a的地址,const修饰a的值不可改变,但是没有说明a的地址不可以改变。我们将它看作一个指针,也就是a的地址可以进行改变,a中存放的内容不可改变。也就间接的可以看作是一个底层const修饰的 &a。底层const不可忽略,所以出现问题。
改正如下:
const int a = 10;
const int *p4 = &a; //同样是顶层const修饰
引用中的const
int &r3 = r1;
int &r4 = 40;
原则:
- 引用不是对象且不会拷贝,所以和顶层const或者底层const的逻辑不通用
- 常量引用如果在左侧,那么右侧可以接任何东西。
int *p1 = &c;
const int *p2 = &c;
const int *const p3 = &c;
const int &r1 = 20;
const int &r2 = *p1;
const int &r3 = *p2;
const int &r4 = *p3;
- 非常量引用 = 常量 ×
int &r5 = 10; //error
- 引号在等号右侧时,忽略&
const int &r6 = 10;
int &r7 = r6;
//忽略等号右侧的&
int &r7 = const int r6; //error:类型不匹配
- 非常量 = 常量引用 √
int b = r6;