找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2296|回復: 0
收起左側

[C++]筆記二十三:C++引用的本質剖析

[復制鏈接]
ID:244281 發(fā)表于 2018-4-3 20:30 | 顯示全部樓層 |閱讀模式
本帖最后由 tyyhmtyyhm 于 2018-4-28 10:02 編輯

第一,引用的意義
1、引用作為其它變量的別名而存,在一些場合可以代替指針;
2、引用相對于指針來說具有更好的可讀性和實用性。(實例可以見之前的交換兩個變量的值程序
第二,引用的本質思考
思考1:引用連接的兩個變量地址相同嗎?
之前我們理解ba的別名,那么變量b有地址嗎?還是跟a地址一樣呢?
我們運行程序:
#include <iostream>
using namespace std;

int main()
{
        //const int a=10;//必須初始化

        int a=10;
        int &b=a; //b很像一個const常量

        cout<<"a="<<a<<endl;//打印a的值
        cout<<"b="<<b<<endl;//打印b的值

//a和b是同一塊內存空間的“門牌號”
        cout<<"&a="<<&a<<endl;//打印a的地址
        cout<<"&b="<<&b<<endl;//打印b的地址

        system("pause");
        return 0;
}
運行結果
a=10
b=10
&a=002EF9FC
&b=002EF9FC
請按任意鍵繼續(xù). . .

發(fā)現(xiàn)ab的地址是一樣的,這說明a和b是同一塊內存空間的門牌號。

思考2:引用占不占內存空間呢?
我們知道引用依附于一個變量,那么引用定義的變量占不占內存空間呢?
我們通過結構體來研究一下這個問題:
在結構體中定義兩個引用變量,看下這兩個引用變量占據(jù)多大的內存,也就是這個看下這個結構體占據(jù)多大的內存。
#include <iostream>
using namespace std;
struct Teacher
{
        char name[64];//64字節(jié)
        int age;      //4個字節(jié)
        int &a;       //多少個字節(jié)?
        int &b;
};
int main()
{
        cout<<"sizeof(Teacher)="<<sizeof(Teacher)<<endl;

        system("pause");
        return 0;
}
運行結果
sizeof(Teacher)=76
請按任意鍵繼續(xù). . .

通過運行我們發(fā)現(xiàn)結構體占了76字節(jié),也就是說每個引用占了4個字節(jié)內存,這個和指針是一樣的!指針也是占4個字節(jié)內存的!
另外,我們知道單獨定義引用時,必須初始化說明引用很像一個const常量。因為定義常量時 const int a = 10;必須初始化進行賦值,如果不初始化就會報錯。
再加上這部分我們探討發(fā)現(xiàn)引用很像一個指針,占據(jù)4字節(jié)的內存。
先對上面兩部分做個小結:
我們看到引用變量b作為a的別名,二者內存地址相同,但是為什么又分別占據(jù)內存呢?援引網(wǎng)上的一句話:由于引用本身就是目標的一個別名,引用本身的地址是一個沒有意義的值,所以在c++中是無法取得引用的內存地址的。取引用的地址就是取目標的地址,c++本身就根本不提供獲取引用內存地址的方法。
第三,引用的本質
1、引用在C++中的內部實現(xiàn)是一個常指針;
Type &name   <----->   Type *const name
2、C++編譯器在編譯過程中使用常指針作為引用的內部實現(xiàn),因此引用所占用的空間大小與指針相同
3、從使用角度,引用會讓人誤認為其只是一個別名,沒有自己的內存空間(目標公用一個內存空間)這是C++為了實用性而做出的細節(jié)隱藏,就是說C++不想讓人們找到引用自己真實的地址,即使你去取引用變量b的地址,也只是目標變量a的地址。
想下指針變量具有一個地址,指針指向的空間也有一個地址,沒有隱藏,很多指針指向一個對象時如果一個指針對對象進行了析構,就會使其他指針變成“野指針”,這就很危險!(該點根據(jù)自己理解,不當之處請指正!

這兩個函數(shù):
void func(int &a) //函數(shù)一
{
        a=5;
}
void func(int *const a) //函數(shù)二
{
        *a=5
}
執(zhí)行函數(shù)一的時候,是C++編譯器在背后在背后通過函數(shù)的方式進行了編譯。編譯C++看到a是一個引用,就會翻譯成函數(shù)二的形式。再看下面的程序:
#include <iostream>
using namespace std;

int modifyA(int &a1)
{
        a1=100;
}
int modifyA2(int *a1)
{
        *a1=200;//【*實參的地址】間接修改實參的值
}
int main()
{
        int a=10;

        //指向這個函數(shù)調用的時候,我們程序員不需要取a得地址
        modifyA(a);
        cout<<"a="<<a<<endl;

        //如果是指針,需要我們程序員手工的取實參的地址
        modifyA2(&a);
        cout<<"a="<<a<<endl;

        system("pause");
        return 0;
}

當我們執(zhí)行函數(shù)modifyA的時候,是C++編譯器自動的取了a的地址傳遞給了a1。執(zhí)行modifyA函數(shù)調用的時候,我們就不需要再取a的地址了C++編譯器幫我們取了。如果是執(zhí)行modifyA2函數(shù),使用指針,就需要傳遞a的地址。
第四,引用小結
先來看間接賦值成立的三個條件:
1、定義兩個變量(一個實參一個形參)
2、建立關聯(lián),實參取地址傳給形參
3*p形參去間接修改實參的值
小結:
1、引用在實現(xiàn)上,只不過是把間接賦值成立的三個條件的后兩步合二為一。實參傳給形參引用的時候,只不過是C++編譯器幫我們程序員自動取了一個實參地址,傳給了形參引用(常量指針)。
2、當我們使用引用語法時,我們不去關心編譯器引用是怎么做的。當我們分析奇怪的語法現(xiàn)象時,我們才去考慮C++編譯器是怎么做的。

【C++】筆記系列均為原創(chuàng),轉載請注明轉自微號:依法編程
更多精彩資料,請關注!


回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復 返回頂部 返回列表