相信學過C++的小伙伴對引用都有了一個概念上的認識,能夠簡單地使用引用編程了,但又感覺糊里糊塗,不明白它到底是什么,它和指針有點相似,但又不是一個東西。
首先舉個例子:
#include <iostream> using namespace std; int main(){ int a = 99; int &r = a; cout<<a<<", "<<r<<endl; cout<<&a<<", "<<&r<<endl; return 0; }
————————————
運行結果:
99, 99
0x28ff44, 0x28ff44
=====================
我們知道,變量是要占用內存的,雖然我們稱 r 為變量,但是通過&r獲取到的卻不是 r 的地址,而是 a 的地址,這會讓我們覺得 r 這個變量不占用獨立的內存,它和 a 指代的是同一份內存。
請讀者再繼續看下面的例子:
#include <iostream> #include <iomanip> using namespace std; int num = 99; class A{ public: A(); private: int n; int &r; }; A::A(): n(0), r(num){} int main (){ A *a = new A(); cout<<sizeof(A)<<endl; //輸出A類型的大小 cout<<hex<<showbase<<*((int*)a + 1)<<endl; //輸出r本身的內容 cout<<&num<<endl; //輸出num變量的地址 return 0; }
————————————
運行結果:
8
0x442000
0x442000
=====================
成員變量 r 是 private 屬性的,不能直接通過對象來訪問,但是借助強大的指針和類型轉換,我們依然可以得到它的內容,只不過這種方法有點蹩腳。
第 20 行代碼中,hex表示以十六進制輸出,showbase表示添加十六進制前綴0x。
從運行結果可以看出:
成員變量 r 是占用內存的,如果不占用的話,sizeof(A)的結果應該為 4。
r 存儲的內容是0x442000,也即變量 num 的地址。
這說明 r 的實現和指針非常類似。如果將 r 定義為int *類型的指針,並在構造函數中讓它指向 num,那么 r 占用的內存也是 4 個字節,存儲的內容也是 num 的地址。
其實引用只是對指針進行了簡單的封裝,它的底層依然是通過指針實現的,引用占用的內存和指針占用的內存長度一樣,在 32 位環境下是 4 個字節,在 64 位環境下是 8 個字節,之所以不能獲取引用的地址,是因為編譯器進行了內部轉換。以下面的語句為例:
int a = 99; int &r = a; r = 18; cout<<&r<<endl;
編譯時會被轉換成如下的形式:
int a = 99; int *r = &a; *r = 18; cout<<r<<endl;
使用&r取地址時,編譯器會對代碼進行隱式的轉換,使得代碼輸出的是 r 的內容(a 的地址),而不是 r 的地址,這就是為什么獲取不到引用變量的地址的原因。也就是說,不是變量 r 不占用內存,而是編譯器不讓獲取它的地址。
當引用作為函數參數時,也會有類似的轉換。
以下面的代碼為例:
//定義函數 void swap(int &r1, int &r2){ int temp = r1; r1 = r2; r2 = temp; } //調用函數 int num1 = 10, num2 = 20; swap(num1, num2); 編譯時會被轉換成如下的形式: //定義函數 void swap(int *r1, int *r2){ int temp = *r1; *r1 = *r2; *r2 = temp; } //調用函數 int num1 = 10, num2 = 20; swap(&num1, &num2);
引用雖然是基於指針實現的,但它比指針更加易用,從上面的兩個例子也可以看出來,通過指針獲取數據時需要加*,書寫麻煩,而引用不需要,它和普通變量的使用方式一樣。
C++ 的發明人 Bjarne Stroustrup 也說過,他在 C++ 中引入引用的直接目的是為了讓代碼的書寫更加漂亮,尤其是在運算符重載中,不借助引用有時候會使得運算符的使用很麻煩。
引用和指針的其他區別
1) 引用必須在定義時初始化,並且以后也要從一而終,不能再指向其他數據;而指針沒有這個限制,指針在定義時不必賦值,以后也能指向任意數據。
2) 可以有 const 指針,但是沒有 const 引用。也就是說,引用變量不能定義為下面的形式:
int a = 20;
int & const r = a;
因為 r 本來就不能改變指向,加上 const 是多此一舉。
3) 指針可以有多級,但是引用只能有一級,例如,int **p是合法的,而int &&r是不合法的。如果希望定義一個引用變量來指代另外一個引用變量,那么也只需要加一個&,如下所示:
int a = 10;
int &r = a;
int &rr = r;
4) 指針和引用的自增(++)自減(--)運算意義不一樣。對指針使用 ++ 表示指向下一份數據,對引用使用 ++ 表示它所指代的數據本身加 1;自減(--)也是類似的道理。
請看下面的例子:
#include <iostream> using namespace std; int main (){ int a = 10; int &r = a; r++; cout<<r<<endl; int arr[2] = { 27, 84 }; int *p = arr; p++; cout<<*p<<endl; return 0; }
————————————
運行結果:
11
84
=====================
- End -
不管你是轉行也好,初學也罷,進階也可,如果你想學編程,進階程序員~
【值得關注】我的 編程學習交流俱樂部 !【點擊進入】
C語言入門資料(網盤鏈接免費分享):

C語言推薦書籍(PDF免費分享):
