C++引用在本質上是什么,它和指針到底有什么區別?


相信學過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免費分享):


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM