C++ Primer Reading Note Chapter 2 (3)

Randy Chen
Randy Chen
Published in
7 min readJul 30, 2019

--

接下來,就是我覺得第二章萬惡的根源const限定詞,哈哈哈。

因為const限定詞用在不一樣的情境下,會影響參考和指標是否需要受const限定詞特性的影響,我覺得有點小小混亂,所以,還是整理一下,爬梳一下自己對const限定詞的認識。

const 限定詞

我們將一個變數的型別定義為const,則該變數的值在初始化之後就不能再被更改。 也因為const變數在被初始化後,就無法被更改了,所以,在宣告const變數的時候,就必須直接對它做初始化的動作。

對const的參考

對const的參考就是宣告一個對const型別的參考。不同於以往的參考,我們不能透過對const的參考,來對被繫結的物件做修改,因為被繫結的物件是const 型別,在初始化後,就不能在被修改了,如果,可以透過參考修改的話,這樣前後的操作就矛盾了,就是下圖代碼第7、8行的程式所呈現的內容。

另外,一般參考去繫結一個const型別的物件是不成立的,如下面程式第9行的部分,錯誤的原因是rval2是一般參考的宣告方式,若這個宣告成立的話,代表我們可以利用rval2來修改底層物件val,但物件val的型別是const int是不能在初始化後,被修改的,這樣會相互矛盾,所以,這種宣告方式不成立。

書中有提到對一般參考宣告時的兩個例外。

一般情況下,參考的型別需與被其所繫結的物件之型別相同。 但事情在const限定詞加入後,變得不再單純 (眉頭一皺><)。

例外一

const型別的參考,可以繫結到一個非const型別的物件(第7行的部分)、字面值(第8的部分)或一個運算式(第9行的部分),就算它所繫結的底層的值再怎麼變化,也不會影響他們的繫結。基本上,就是不要透過對const的參考來更改它底層的物件,你要在它初始化的時候,做以上那些情況的設定,都是沒問題的。

例外二

將一個const型別的物件去繫結一個基礎型別不同的物件,可以這樣做嗎? 答案是,可以。

如下圖所示,如果今天我們用一個const int型別的參考去繫結一個double物件,那編譯器會先自己創出一個const int型別的temp_val參考去繫結val,最後,才讓我們自己創的參考rval去繫結編譯器自己創的temp_val,所以,實際上rval繫結到的物件並不是val本人!!

將以上這個觀念進行延伸,如果,我們今天用一般型別的參考去繫結一個不同基礎型別的物件會發生什麼事??!! 答案是,不行!!!

如同下圖所示,編譯器一樣會自己先創一個const int 型別的參考temp_val去跟val做繫結,但當我們用rval去跟temp_val做繫結的時候,就會帶到前面所講到的觀念,我們不能用一般參考去繫結一個const int 型別的物件。

所以,以下這種參考的宣告方式是錯誤的。

對const的指標

對const的指標顧名思義,就是一個指向const型別物件的指標。跟參考的例子一樣,我們不能用一個基礎型別的指標去指向一個const型別的物件,假若這種宣告成立,就代表我們可以用這個一般型別的指標來修改底層的物件,但底層的物件又是const型別,是不能被修改的,這樣會前後矛盾(第7行),所以,我們也需要對const型別的指標去指向一個const型別的物件(第8行)。

跟參考類似,在我們可以將同樣型別的指標,指向同樣型別的物件的情況是有例外的。也就是,我們能將const型別的指標指向非const型別的物件。如下圖的第8、9行所示,但是,我們不能透過它來改變底層物件的值,因為它是指向"const int"型別的物件,而const int型別的物件是不能更改其值的。

const指標

書中有講到一句話,我覺得還蠻重要的,它說與參考不同的是,指標本身是一個物件,所以,指標可以被宣告成一個const指標。

宣告方式就是*const。

小心!!! const只是放置的位置要放在指標名稱的前面而已,不代表它所指的物件的型別喔!!

而const指標就變的跟其他的const的物件特性相同

首先,必須一開始就被初始化,

第二,其初始化所指向的對象,在初始化過後就不能再更改了。

我在念這邊的時候,有點小小的跟對const指標的狀況搞混了,搞混的情形如下

尤其是第9–16行的部分。

對const的指標代表這個指標本身並不是一個const物件,它只是指向一個const型別的物件而已,是一個旁觀者的角度,所以,它不受const限定詞的約束,可以在宣告初期不馬上對它設值(第10行),且可以變換指向的對象(第11, 12行),但是它不能用來更改底層物件的內容,因為它所指向的底層物件是一個const型別的物件(第13行)。

而const指標,就是一個當局者,它本身就是const的物件,所以,它當然需要被const限定詞的特性所限制,像是必須在宣告初期就馬上進行設值(第14行),它在初始化後,我們就不能再更改它所繫結的對象(第15行),我們可以透過它來更改底層物件的值,因為它指向的值不是const型別(第16行)。

讀到這邊我覺得 沒有受const限定詞特性限定有受const限定詞特性限定,就是 對const的指標 和 const指標 之間,讓我很容易搞混的兩個地方,但只要搞清楚在什麼情況下指標是旁觀者,在什麼其況下指標是當局者,如此,就比較能分清楚當有const加入指標的宣告時,他們能做什麼又不能做什麼了。

總結一下,

int val1 = 0, val2 = 10;

const int val 3 =12;

一般參考

int &rval = val1; // 不能更改繫結對象,可以更改底層物件的值

對const的參考

const int &rval1 = val3; // 不能更改繫結對象,不能更改底層物件的值

const int &rval2 = val1; // 可以繫結非const型別的物件

一般指標

int ptr = &val;

ptr = &val2; // 一般指標可以變換指向對象,但是,不能指向const 型別的物件

*ptr = 60; // 可以更改底層物件的值

對const的指標

const int *ptr1 = &val1; // 可指向非const型別的物件

ptr1 = &val2; // 可變換指向的對象,但不行利用它來更改底層物件的值

const指標

int *const ptr2 = &val1; // 可以指向一般型別物件

ptr2 = &val2; // 不能改變指向的對象

*ptr2 = 100; //可以更改底層物件的值

int *const ptr3 = &val3; // 不能指向const型別的物件

--

--

Randy Chen
Randy Chen

Keep fertilizing it, Keep watering it, Keep marching on