什麼是 頂層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;