隨著程序的越來越復雜,程序中用到的類型也越來越復雜,體現在兩個方面:
- 類型名稱難于拼寫,名字既難記由容易寫錯,還無法確定其真實目的是什么
- 有時候根本不知道所需要的類型是什么,我們必須從上下文尋求幫助
這時候我們主要有三種解決方案:
- 類型別名
類型別名是一個名字,是某種類型的一個同義詞。
傳統方法定義別名用的是typedef:
typedef double wages; //wages是double的同義詞
wages hourly, weekly; //等同于double hourly, weekly;
C++11標準規定了一種新的辦法,即使用別名聲明,using:
using wages = double; //wages是double的同義詞
wages hourly, weekly; //等同于double hourly, weekly;
這里需要注意的是,假如某個類型別名指代的是復合類型或者常量,那么把它用到聲明語句里就會產生意想不到的后果:
typedef char *pstring;
const pstring cstr = 0; //cstr指向char的常量指針
const pstring *ps; //ps是一個指針,它的對象是指向char的常量指針
這里必須要明白,pstring實際上是指向char的指針,所以const pstring就是指向char的常量指針,而非指向常量字符的指針,不能簡單的將類型別名替換成他本來的樣子:
const char *cstr = 0; //這是對const pstring cstr的錯誤理解
2.auto類型說明符
在我們編程的時候,常常需要把表達式的值賦值給變量,這要求在聲明變量的時候知道表達式的類型,然而這一點是很不容易的,所以C++11引入了auto說明符來幫助我們推斷表達式所屬的類型,由auto的特性我們知道,auto定義的變量必須有初始值。
這里我們要注意的是,auto可以在同一條語句中聲明多個變量,但是一條語句中只能有一個基本數據類型,所以該語句中所有的初始基本數據類型都必須一樣:
auto i = 0, *p = &i; //正確,i是整型,p是整型指針
auto sz = 0, pi = 3.14 //錯誤,sz是整型, pi是浮點型
使用auto我們還必須要注意以下幾點:
- 首先,和我們之前所知道的一樣,使用引用其實就是使用引用的對象,特別的是,當引用作為初始值的時候,參與初始化的實際上是引用的對象的值。所以,編譯器此時以引用對象的類型作為auto的類型:
int i = 0, &r = i;
auto a = r; //a是int型(r是i的別名,而i是int型)
- 其次,auto一般會忽略頂層const,同時底層const會被保留下來:
const int ci = i, &cr = ci;
auto b = ci; //b是int型(ci的頂層const被忽略)
auto c = cr; //c是int型(cr是ci的別名,ci的頂層const被忽略)
auto d = &i; //d是指向int型的指針
auto e = &ci; //e是指向int型常量的指針
- 如果希望推斷出來的是一個頂層const,需要明確的指出:
const auto f = ci; //ci的推演類型是int,而f是const int
- 還可以將引用的類型設置為auto,此時原來的初始化規則仍然適用:
auto &g = ci; //g是一個整型常量引用,綁定到ci
auto &h = 42; //錯誤,非常量引用不可綁定字面值
const auto &j = 42; //正確,常量引用綁定字面值
設置一個auto的引用的時候,初始值中的頂層常量屬性仍然保留
- 要在一條語句中定義多個變量,切記,符號&和*只從屬于某個聲明符,而非基本數據類型的一部分,因此初始值必須是同一種類型:
auto k = ci, &l = i; //k是int型, l是int型引用
auto &m = ci, *p = &ci; //m是int型常量引用,p是指向int型常量的指針
auto &n = i, *p2 = &ci //錯誤,n是int型引用,而p2必須是指向int型常量的指針,這里確實指向int型的普通指針
3.decltype類型指示符
有時候會碰到這樣的情況,我們想用某個表達式的類型定義某個變量,但是不想用該表達式的值初始化這個變量。C++11給我們提供了decltype說明符,它的作用是返回操作數的數據類型。
decltype處理底層const和引用的方式與auto不同。如果decltype使用的表達式是一個變量,那么decltype返回該變量的類型(包括頂層const和引用在內):
const int ci = 0, &cj = ci;
decltype(ci) x = 0; //x的類型是const int
decltype(cj) y = x; //y的類型是const int &
decltype(cj) z; //錯誤,z的類型是const int &,必須初始化
下面讓我們看一組有趣的情況:
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;
decltype(*p) c
在上述的代碼中,decltype(r + 0)返回的類型是int型,這是因為,r作為表達式的一部分,r + 0實際上參與運算的是i + 0,返回的是一個具體的值,而非引用,是int型,但是decltype(r)返回的類型是int &,這點需要明白。
最后一點需要懂得的是,如果decltype使用的是一個不加括號的變量,那么得到的結果是這個變量的類型,一旦加上括號,得到的是引用類型:
decltype((i)) d; //錯誤,d是一個int &,必須初始化
decltype(i) e; //正確,e是一個為初始化的int型變量