2.3複合類型
複合類型就是隻基于其它類型定義的類型,本次将介紹兩種引用和指針
2.3.1 引用
在c++11中用兩種引用,有右值引用和左值引用,右值引用我們将在13.6.1節中繼續學習,而我們常說的引用為左值引用
引用換句話來說,就是為對象取了另一個名字,自生并非對象,通過将聲明符寫成“&”+“變量名”來定義引用類型,因為是為一個對象取地别名,是以其必須有明确的對象,即必須被初始化
引用的定義就表明着與對象的綁定,對其的操作都是在與之綁定的對象上完成的
引用自身并不是對象是以不能定義引用的引用,并且引用的類型要與與之綁定的類型要比對
2.3.2 指針
指針(pointer) 是“指向(point to)”另外種類型的複合類型。與引用類似,指針也實作了對其他對象的問接通路。然而指針與引用相比又有很多不同點。其一,指針本身就是一個對象,允許對指針指派和拷貝,而且在指針的生命周期内它可以先後指向幾個不同的對象。其二,指針無須在定義時賦初值。和其他内置類型樣, 在塊作用域内定義的指針如果沒有被初始化,也将擁有一個不确定的值。
指針可以指向一個對象,指針内儲存對象的位址,可以通過通路位址間接通路那個對象
定義指針類型的方法将聲明符寫成d的形式,其中d是變量名。如果在一條語 句中定義了幾個指針變量,每個變量前面都必須有符号:
int *ip1, *ip2; // ip1 和ip2都是指向int型對象的指針
double dp, *dp2; // dp2 是指向double型對象的指針,dp是double型對象擷取對象的位址
指針存放某個對象的位址,要想擷取該位址,需要使用取位址符(操作符&);
int ival = 42
int *P = &ival; // p存放變量ival的位址,或者說p是指向變量ival的
指針第二條語句把p定義為一個指向int的指針,随後初始化P令其指向名為ival的in對象。因為引用不是對象,沒有實際位址,是以不能定義指向引用的指針。
除了2.4.2節(第56頁)和15.2.3 節(第534頁)将要介紹的兩種例外情況,其他有指針的類型都要和它所指向的對象嚴格比對:
double dval;
double *pd = &dval; // 正确:初始值是double型對象的位址
double *pd2 = pd
/正确:初始值是指向double對象的指針
int *pi = pd;
/錯誤:指針pi的類型和pd的類型不比對
)i = &dval;
/錯誤:試圖把double型對象的位址賦給int型指針
因為在聲明語句中指針的類型實際上被用于指定它所指向對象的類型,是以二者必須呢。如果指針指向了一個其他類型的對象, 對該對象的操作将發生錯誤。
指針值
指針的值(即位址)應屬下列4種狀态之一+
1.指向一個對象。
2.指向緊鄰對象所占空間的下一個位置。
3.空指針,意味着指針沒有指向任何對象。
4.無效指針,也就是上述情況之外的其他值。
就算是第二,第三種可能是有效的指針但如果沒有指向任何對象,通路此類的指針是不被允許的,且很容易出錯
利用指針通路對象
如何運用指針通路指向的對象,就要運用到解引用符“*”,對指針的解引用會得出所指的對象,是以如果給解引用的結果指派,實際上也是給指針所指的對象指派
空指針
因為沒有指向的指針是很危險的,是以我們經常要将定義好的指針再賦給它(使其指向)一處人畜無害的空區
int *p1 = nullptr;
//等價于int *pl= 0;
int*p2 = 0;
//直接将p2初始化為字面常量0
//需要首先#include cstdlib
int *p3 = NULL;
//等價于int*p3=0;
過去的程式中常用到名為NULL的預處理變量,來給指針指派,這個變量在頭檔案cstdlib中定義,其值為0.預處理器是指運作編譯過程之前就的一段程式,預處理不屬于命名空間std。
在新的标準之下,現在的c++程式盡量使用nullptr,避免使用NULL
建議初始化所有的指針,并且在可能的情況下,盡量等定義了對象之後再定義指向它的指針。
指派和指針
指針和引用都能提供對其他對象的間接通路,然而在具體實作細節上二者有很大不同,其中最重要的點就是引用本身并非一個對象。一旦定義了引用, 就無法令其再綁定到另外的對象,之後每次使用這個引用都是通路它最初綁定的那個對象。
指針和它存放的位址之間就沒有這種限制了。和其他任何變量(隻要不是引用)一樣,給指針指派就是令它存放一個新的位址,進而指向一個新的對象:
有時候要想搞清楚- 條指派語句到底是改變了指針的值還是改變了指針所指對象的值不太容易,最好的辦法就是記住指派永遠改變的是等号左側的對象。
其他指針操作
無論是作為條件出現還是參與比較運算,都必須使用合法指針,更多介紹在3.5.3節
void*指針
void*指針是一種特殊的指針,能存放任意類型的對象,但相對于普通指針,也僅僅能存放位址,無法直接操作所指向的對象,因為對象類型不知道
利用void指針能做的事兒比較有限,拿它和别的指針比較、作為函數的輸入或輸出,或者賦給另外一個 void指針。不能直接操作void指針所指的對象,因為我們并不知道這個對象到底是什麼類型,也就無法确定能在這個對象上做哪些操作。
概括說來,以void的視角來看記憶體空間也就僅僅是記憶體空間,沒辦法通路記憶體空間中所存的對象,關于這點将在19.1.1 節有更詳細的介紹,4.11.3節将講述擷取void指針所存位址的方法。
2.3.3 了解複合類型的聲明
一條語句中,雖然基本資料類型是相同的,但是聲明符的形式可以不同
聲明符包括了類型修飾符(*和&)
定義多個變量
涉及指針或引用的聲明,一般有兩種寫法
1.将修飾符和變量辨別符寫在一起。這種形式強調變量具有的複合類型(常用)
int *p1,*p2;
2.将修飾符和類型名寫在一起,并且每條語句隻定義一個變量(避免以為相關類型修飾符作用于全局)(少用)
提示:選擇兩種方法的關鍵在于,選擇并堅持一種寫法,不要總是變來變去