1. 程式人生 > >為什麼C++中常量引用可以繫結非常量的物件、字面值和一般表示式 詳解

為什麼C++中常量引用可以繫結非常量的物件、字面值和一般表示式 詳解

    在c++語言中,除兩種例外情況,其他引用的型別都要和與之繫結的物件嚴格匹配,如int型的引用只能繫結int型的物件;並且引用不能直接與字面值常量或表示式結果繫結。

    其中一種例外情況是:初始化常量引用時,允許用任意表達式作為初始值,只要該表示式的結果能轉換成引用的型別即可。允許為一個常量引用繫結非常量的物件、字面值,甚至是個一般表示式。例如:

// 以下例子來自《Primer c++ 第五版》
int i = 42;
const int &r1 = i;      // 正確
const int &r2 = 42;     // 正確
const int &r3 = r1 * 2; // 正確

    接下來看一個更復雜的例子,並通過這個例子來講解為什麼常量引用是個例外。

double dval = 3.14;
// int &a = dval;    // 編譯錯誤,因為普通引用的型別要與物件型別一致
const int &b = dval; // 編譯正確
    c++的自動型別轉換機制中,當用一個double去初始化int時,會捨棄掉小數轉換為int。在上面的例子中,編譯後的程式碼實際是這樣的:
double dval = 3.14;
const int temp = dval; // 由double生成了一個臨時的整形常量
const int &b = temp;   // 讓b繫結這個臨時量
    程式碼中的改變當然是由編譯器完成的。

    在這種情況下,引用繫結的是一個臨時量物件而不是dval本身。臨時量物件就是:當編譯器需要一個空間來暫存表示式的求值結果時,臨時建立的一個未命名的物件。

    顯然,c++認為,常量引用可以繫結這個臨時量,而普通引用就不能繫結這個臨時量。

    因為c++認為,使用普通引用繫結一個物件,就是為了能通過引用對這個物件做改變。如果普通引用繫結的是一個臨時量而不是物件本身,那麼改變的是臨時量而不是希望改變的那個物件,這種改變是無意義的。所以規定普通引用不能繫結到臨時量上。

    那麼為什麼常量引用就可以呢,因為常量是不能改變的。也就是說,不能通過常量引用去改變物件,那麼繫結的是臨時量還是物件都無所謂了,反正都不能做改變也就不存在改變無意義的情況。

    所以常量引用可以繫結臨時量,也就可以繫結非常量的物件、字面值,甚至是一般表示式,並且不用必須型別一致。

    這裡的邏輯有點繞,可能多花點時間才能理解。其實不理解也無所謂,死記語法也是正常操作。