類型別名
程序越復雜,程序的類型也會越復雜。類型復雜體現在兩點:
1、 難於拼寫,且不能體現其真實目的和含義。
2、 程序員不了解程序的情況下,無法確定需要聲明什麼樣的類型。
類型別名可使程序的類型名字變得簡單明了、易於理解和使用。類型別名需要使用typedef關鍵字,如:
1 typedef double wages; //wages和double是同義詞。wages含義和目的比double更明確,也更易於程序員在不了解程序的情況下,確定什麼樣的變量需要聲明為wages。 2 typedef wage base , *p; //base是double的同義詞,p是double*的同義詞。
C++11新標准可使用using關鍵字聲明類型別名,如:
1 using wages = double; //wages是double的同義詞,等價於typedef double wages;
類型別名和類型的名字等價,只要是類型的名字能出現的地方,就能使用類型別名。
另外,使用類型別名聲明const的指針時,需要注意理解下面第三行代碼:
1 int i = 0; 2 using pint = int *; 3 const pint ci = &i; //ci是指向int的常量指針,而非指向常量int的指針。
特別注意的是pint不能簡單的替換成int *,理解成:
1 const int *ci = &i; //這裡ci是指向常量int類型的指針,而非指向int的常量指針。
為了解釋這種情況,我們可以這樣理解:聲明語句中用到的pint,其基本數據類型是指針。可是替換成int *重寫聲明語句後,數據類型變成了int,*成了聲明符的一部分,這樣的結果是:const int成了基本數據類型,指針ci指向const int;而當pint是基本數據類型時,基本類型就是一個指針,const pint表示指針是常量,所以ci就是常量指針,它指向int數據類型。
auto類型說明符
在把表達式的值賦給變量,就要求聲明變量的時候清楚知道表達式的類型。然而要做到這一點並非那麼容易,有時根本做不到。為了解決這個問題,C++11新標准引入了auto類型說明符。
1 auto item = val1 + val2; //由val1和val2相加的結果可以推斷出item的類型
auto能讓編譯器替我們去分析表達式所屬的類型。通過初始值來推算變量的類型。顯然,auto定義的變量必須有初始值。 使用auto也能在一條語句中聲明多個變量:
1 auto i = 0, *p = &i; //正確 2 auto sz = 0, pi = 3.14; //錯誤:sz和pi的類型不一致。
需要注意的是auto一般會忽略掉頂層const(聲明指向常量變量的常量指針時:const char * const pc = 0,第一個const是底層,第二個const是頂層),同時底層const會保留下來,如:
1 const int ci = i, &cr = ci; 2 auto b = ci; //b是一個整數(ci的頂層const特性被忽略掉了) 3 auto c = cr; //c是一個整數(cr是ci的別名,ci本身是一個頂層const) 4 auto d = &i; //d是一個整形指針 5 auto e = &ci;//e是一個指向整數常量的指針(對常量對象取地址是一種底層const)
如果希望推斷出的auto類型是一個頂層const,需要明確指出:
1 const auto f = ci;
另外,還可以將引用類型設為auto:
1 auto &g = ci; //g是一個整形常量的引用,綁定到ci。
decltype類型指示符
有時我們希望從表達式的類型來定義變量的類型,但是不想用該表達式的值初始化變量。可以使用decltype類型指示符。
1 decltype(f()) sum = x; //sum的類型就是函數f的返回類型。
編譯器並不實際調用函數f,而是當調用發生時,使用f的返回值類型作為sum的類型。
decltype處理頂層const和引用的方式與auto有些許不同。如果decltype使用的表達式是一個變量,則decltype返回該變量的類型,包括頂層const和引用在內。如:
1 const int ci = 0, &cj= ci; 2 decltype(ci) x = 0; //x的類型是const int。 3 decltype(cj) y = x; //y的類型是const int &, y綁定到變量x。 4 decltype(cj) z; //錯誤:z是一個引用,必須初始化。
decltype和引用:
當decltype使用的表達式不是變量,則返回表達式結果對應的類型。而且有些表達式將向decltype返回一個引用類型:
1 int i = 42, *p = &I, &r = i; 2 decltype(r + 0) b; //正確:加法的結果是int,因此b是一個未初始化的int。 3 decltype(*p) c; //錯誤:c是int &,必須初始化。
因為r是一個引用,因此decltype(r)的結果也是引用類型,而表達式r+0的結果顯然是一個具體的值,而非一個引用。另一方面,如果表達式的內容是解引用操作,則decltype也將得到引用類型。因為解引用指針可以得到指針所指的對象,而且還能給這個對象賦值。因此,decltype(*p)的結果類型就是int &,而非int。
decltype和auto的另一處重要區別是,decltype的結果類型和表達式的形式密切相關。如:
1 decltype((i)) d; //錯誤:d是int &,必須初始化。 2 decltype(i) e; //正確:e是一個(未初始化的)int。
上述代碼中,如果i變量不加括號,得到的結果是該變量的類型。如果i變量加括號,編譯器就會把它當成是一個表達式。變量是一種可以作為賦值語句左值的特殊表達式,所以這樣的decltype就會得到引用類型。