【C++100問】深入理解理解頂層const和底層const

我是管小亮發表於2020-01-29

歡迎關注WX公眾號:【程式設計師管小亮】

專欄C++學習筆記

宣告

1)該文章整理自網上的大牛和相關專家無私奉獻的資料,具體引用的資料請看參考文獻。
2)本文僅供學術交流,非商用。所以每一部分具體的參考資料並沒有詳細對應。如果某部分不小心侵犯了大家的利益,還望海涵,並聯系博主刪除。
3)博主才疏學淺,文中如有不當之處,請各位指出,共同進步,謝謝。
4)此屬於第一版本,若有錯誤,還需繼續修正與增刪。還望大家多多指點。大家都共享一點點,一起為祖國科研的推進添磚加瓦。

〇、前言

最近在恢復寫部落格,較真之前寫過的部落格——《C++ Primer》學習筆記(二):變數和基本型別,看到了關於【頂層const和底層const】,但是一直不解其意,就簡單總結一下在網上看到的相關資料,方便理解,相關說明可以看上面的宣告。

個人C++專欄(最近會一直更新的):

一、頂層const和底層const對比

《C++primer》中寫到:

  • 頂層 const 表示指標本身是個常量;
  • 底層 const 表示指標所指的物件是一個常量。

指標型別既可以是頂層 const 也可以是底層 const

int i = 0;
int *const p1 = &i;       // 不能改變p1的值,這是一個頂層const
const int ci = 42;        // 不能改變ci的值,這是一個頂層const
const int *p2 = &ci;      // 允許改變p2的值,這是一個底層const
const int *const p3 = p2; // 靠右的const是頂層const,靠左的const是底層const
const int &r = ci;        // 用於宣告引用的const都是底層const

即(除了 const int ci = 42; //頂層const):

  • 如果 const 右結合修飾的為 型別 或者 *,那這個 const 就是一個底層 const
  • 如果 const 右結合修飾的為 識別符號,那這個 const 就是一個頂層 const

非官方定義,用來記憶為主。


不過個人感覺更好的理解還是 stackoverflow——What are top-level const qualifiers? 上的,總結來說:

  • 被修飾的變數本身無法改變的 const 是頂層 const
  • 通過指標或引用等間接途徑來限制目標內容不可變的 const 是底層 const

給了兩個例子:

// 底層const
char x;
char const* p = &x;

// 頂層const
char x = 't';
char *const p = &x;

當然還有輪子大神的解釋 知乎——頂層const與底層const。C++的物件中的物件究竟是指?

在這裡插入圖片描述
我的理解是 const 的位置很重要,即 const intint const 的區別非常重要,不過我還不能完全理解這其中的區別,可能學完能有一個新的認識吧。。。fighting!


小結一下: 主要的理解問題基本可以得到解決,認識哪一個是什麼即可,這一點上 stackoverflow 顯然更清晰,除此之外,最大的問題應該是中文對於底層 const 的翻譯,英文原文的兩個單詞是:

  • top-level const 頂層 const
  • low-level const 底層 const

對的,你沒看錯,是 low 而不是 bottom。。。所以或許成為低層更恰當???

二、頂層const和底層const區別

當執行拷貝操作時,常量是頂層 const 還是底層 const 的區別就非常明顯了:

  • 頂層 const 沒有影響。拷貝操作不會改變被拷貝物件的值,因此拷入和拷出的物件是否是常量無關緊要。
i = ci;     			// ok: 拷貝ci的值,ci是一個頂層const,對此操作無影響
p2 = p3;    			// ok: p2和p3指向的物件型別相同,p3頂層const的部分不影響
  • 底層 const 的限制不能忽視。拷入和拷出的物件必須具有相同的底層 const 資格,或者兩個物件的資料型別可以相互轉換(一般來說,非常量可以轉換成常量,反之則不行)。
int *p = p3;    		// error: p3包含底層const的定義,而p沒有
p2 = p3;        		// ok: p2和p3都是底層const
p2 = &i;        		// ok: int*能轉換成const int*
int &r = ci;    		// error: 普通的int&不能繫結到int常量上
const int &r2 = i;  	// ok: const int&可以繫結到一個普通int上

三、剝洋蔥

最後舉一個例子,證明【剝洋蔥】,從右向左看更容易理解:

const int *p // p是指標,指向int,int是const, 「*p」型別為int並且不可變;是低層const;
int *const p // p是const,是常量指標,指向int, p屬於「int *」並且不可變;是頂層const;

參考文章

相關文章