C++ 中變數宣告中 const 用法
一直以來對 C++ 中的 const 說明符理解不夠清晰,尤其是在變數宣告時處於何種位置起到何種作用,分辨不清。
現在花費一些時間專門理清其中的關係,明白其中的道理之後,就再也不會混淆了。文中內容主要參考了這篇譯文。
1. 幾個概念
以 static unsigned long int *x[N];
為例,說明幾個概念
- 宣告符:一個宣告符就是被宣告的名稱,可能伴有操作符和識別符號,這裡為
*x[N]
; - 操作符:如
*
,[]
,()
, 和(C++中的)&
. 正如你所知的,宣告中的符號*
表示“指標”,[]
表示 “序列”; - 識別符號:一個宣告符可能包含不止一個識別符號。宣告符
*x[N]
x
和N
。只有其中一個識別符號是被宣告的,而且被稱為是宣告符ID,其餘的必須在這之前就被宣告過。舉例,*x[N]
中的宣告符ID是x
。 - 說明符:可以包括型別說明符,如
int
,unsigned
,他們也可以是儲存類說明符,如extern
或static
。在C++中,他們也可以是函式說明符,如inline
或virtual
,const
和volat
關鍵詞都是型別說明符。
現在可以說,變數宣告語句 static unsigned long int *x[N];
是由宣告符和說明符來組成的。其中宣告符由操作符和識別符號組成,說明符可以同時含有型別說明符、儲存類說明符等。
2. 解析順序
所謂的解析順序,我理解分為兩個部分,宣告符說明了是一個什麼東西,說明符給出了這個東西的一些性質。對宣告符來說,解析順序決定了這個東西屬於什麼大類,什麼小類,說明符不區分順序,給出了這個東西在不同方面的屬性。
2.1 操作符解析順序
可以按照這個規則來決定解析順序:離識別符號ID越近,越決定了目標先是什麼,距離相等情況下操作符優先順序越高越先解析。
舉例來說,*x[N]
中 *
和 []
離識別符號ID x
的距離相等,按照 C++ 符號優先順序圖表進行解析, []
的優先順序比 *
更高,因此宣告符 *x[N]
表明 x
是一個優先於指標的序列,也就是說,它首先是一個序列,其次序列中的每個元素是一個指標。如果想要變換解析順序,可以應用 ()
(*x)[N]
表示為一個指向序列為 N
的指標。
2.2 說明符解析順序
宣告說明符在一個宣告中出現的順序並不重要。比如 const unsigned static int
、static unsigned int const
、int const unsigned static
、const int static unsigned
,只不過通常大家有一套預設的書寫順序。
2.3 const
和 volatile
能出現在宣告符中的宣告說明符只有 const
和 volatile
。當出現在宣告符中時,可以認為其修飾的物件變成了操作符,並且不能交換 const
或 volatile
在宣告中的順序(不能交換const
或 volatile
與操作符*
的順序)。例如 int const *a
把 a
宣告為指向 const int
的指標,而 int *const a
把 a
宣告為指向 int
的 const 指標。
2.4 最終的解析順序
參考文章中總結到:
C++基本上是按從頭到尾、從左到右的順序來讀,但是指標的宣告,從某種意義來講卻是倒著的。指標的宣告是從右到左來看。把
const
放在其他型別說明符的右邊,可以嚴格的從右到左來看指標宣告,還可以把const
從“右邊的”位置提出來,如:T const *p
; 把p
宣告為“指向const T
的指標”,非常準確,同樣:T *const p
; 把p
宣告為“指向T
的 const 指標”,也能正確的理解。
按照我自己的理解,可以按照先確定是什麼東西(宣告符),再看這個東西的性質(說明符)順序來確定。
以上面例子來說,T const *p
先確定是一個指標,再看這個指標是關於 const T
型別的,也就是“指向 const T
的指標”;T *const p
先確定時一個 const 指標,再看這個 const 指標是關於 T
型別的,也就是“指向 T
的 const 指標”。
3. 宣告風格
- 當把變數宣告語句分成說明符和宣告符兩大部分之後,可能比較好理解文中給出的陳述:
const int* p
; 而不是const int *p
;
- 依照參考文章中對宣告順序的理解,給出的另一個建議:
const void *vectorTable[]
(3)void const *vectorTable[]
(4) 大多數C和C++程式設計師更喜歡把const和volatile寫在其他型別的說明符的左邊,同(3)。而我更喜歡把const和volatile寫在右邊,如(4),而且強烈推薦這樣寫。