C++的引用首先跟指針的最大區別就是引用不是一個對象,而指針是一個對象;其次引用在其定義時就要初始化,而指針可以不用。
int val = 42; int &rval = val;
此時rval就綁定了val,其實就是rval就是val的一個別名。你修改了兩個其中的一個,其值都會改變。
因為引用在一開始就初始化了,所以一個引用只能引用一個變量。還有,引用只能引用對象,也就是有地址的,不能是一個常數或者表達式。而且類型要匹配。
int &rval = 10; //error: initializer must be an object double dval = 3.14; int &rdval = dval; //error: initializer must be an int object
References to const 常量引用
不同於非常量的引用,常量引用所引用的對象不能修改
const int ci = 1024; const int &r1 = ci; r1 = 42; //error: r1 is a reference to const int &r2 = ci; //error: nonconst reference to a const object
因為ci是一個常量,所以我們不能直接用一個引用來引用ci,因為我們不能修改ci。
上面提到引用要引用正確的自身的類型,但是常量引用可以引用一個非const的對象,一個數,或者表達式。
int i = 42; const int &r1 = i; //ok const int &r2 = 42; //ok const int &r3 = r1 * 2; //ok int &r4 = r * 2; //error: 非常量引用不能引用一個表達式
讓我們想想這是為什麼?
double dval = 3014; const int &ri = dval; //ok
其實編譯器幫我們多做了一步
double dval = 3014; const int temp = dval; //創建一個暫時的常量對象來存放dval const int &ri = temp; //將引用到這個暫時的常量
正因為有這個無名的中轉存量,所以常量引用才可以引用數,表達式,還有不同類型的對象。
那為什麼非常量引用就不能這樣呢?
想想,剛才說的編譯器幫我們弄了一個中轉對象,其實我們引用是引用它,修改也修改它, 但它是無名的,也就是找不到地址,也無法找著。修改了也沒用,我們是要修改dval(在上面列子中)。
所以說,只有常量引用才可以引用數字,表達式,不同類型的對象。因為我們不打算修改它,所以那個中轉變量真的只是負責傳遞值,讓常量引用初始化而已。
最後一個例子
int i = 42; int &r1 = i; const int &r2 = i; r1 = 0; //ok r2 = 0; //error
這樣非常量引用和常量引用都引用一個值是可以的。非常量引用就不用說了,跟對象綁在一起,是別名,修改引用的同時也就修改了對象本身的內容。而常量引用,就是跟上面一樣,編譯器幫我們創建了一個無名的中轉變量來儲存,其實也就是賦值給常量對象初始化。你不能修改它就是了。