本帖最后由 tyyhmtyyhm 于 2018-4-28 10:02 編輯
第一,引用的意義1、引用作為其它變量的別名而存在,在一些場(chǎng)合可以代替指針; 2、引用相對(duì)于指針來說具有更好的可讀性和實(shí)用性。(實(shí)例可以見之前的交換兩個(gè)變量的值程序) 第二,引用的本質(zhì)思考思考1:引用連接的兩個(gè)變量地址相同嗎? 之前我們理解b是a的別名,那么變量b有地址嗎?還是跟a地址一樣呢? 我們運(yùn)行程序: #include <iostream> using namespace std;
int main() { //const int a=10;//必須初始化
int a=10; int &b=a; //b很像一個(gè)const常量
cout<<"a="<<a<<endl;//打印a的值 cout<<"b="<<b<<endl;//打印b的值
//a和b是同一塊內(nèi)存空間的“門牌號(hào)” cout<<"&a="<<&a<<endl;//打印a的地址 cout<<"&b="<<&b<<endl;//打印b的地址
system("pause"); return 0; } 運(yùn)行結(jié)果: a=10 b=10 &a=002EF9FC &b=002EF9FC 請(qǐng)按任意鍵繼續(xù). . .
發(fā)現(xiàn)a和b的地址是一樣的,這說明a和b是同一塊內(nèi)存空間的“門牌號(hào)”。
思考2:引用占不占內(nèi)存空間呢? 我們知道引用依附于一個(gè)變量,那么引用定義的變量占不占內(nèi)存空間呢? 我們通過結(jié)構(gòu)體來研究一下這個(gè)問題: 在結(jié)構(gòu)體中定義兩個(gè)引用變量,看下這兩個(gè)引用變量占據(jù)多大的內(nèi)存,也就是這個(gè)看下這個(gè)結(jié)構(gòu)體占據(jù)多大的內(nèi)存。 #include <iostream> using namespace std; struct Teacher { char name[64];//64字節(jié) int age; //4個(gè)字節(jié) int &a; //多少個(gè)字節(jié)? int &b; }; int main() { cout<<"sizeof(Teacher)="<<sizeof(Teacher)<<endl;
system("pause"); return 0; } 運(yùn)行結(jié)果: sizeof(Teacher)=76 請(qǐng)按任意鍵繼續(xù). . .
通過運(yùn)行我們發(fā)現(xiàn)結(jié)構(gòu)體占了76個(gè)字節(jié),也就是說每個(gè)引用占了4個(gè)字節(jié)內(nèi)存,這個(gè)和指針是一樣的!指針也是占4個(gè)字節(jié)內(nèi)存的! 另外,我們知道單獨(dú)定義引用時(shí),必須初始化:說明引用很像一個(gè)const常量。因?yàn)?font face="宋體">定義常量時(shí) const int a = 10;必須初始化,進(jìn)行賦值,如果不初始化就會(huì)報(bào)錯(cuò)。 再加上這部分我們探討發(fā)現(xiàn)引用很像一個(gè)指針,占據(jù)4個(gè)字節(jié)的內(nèi)存。 先對(duì)上面兩部分做個(gè)小結(jié): 我們看到引用變量b作為a的別名,二者內(nèi)存地址相同,但是為什么又分別占據(jù)內(nèi)存呢?援引網(wǎng)上的一句話:由于引用本身就是目標(biāo)的一個(gè)別名,引用本身的地址是一個(gè)沒有意義的值,所以在c++中是無法取得引用的內(nèi)存地址的。取引用的地址就是取目標(biāo)的地址,c++本身就根本不提供獲取引用內(nèi)存地址的方法。 第三,引用的本質(zhì)1、引用在C++中的內(nèi)部實(shí)現(xiàn)是一個(gè)常指針; Type &name <-----> Type *const name 2、C++編譯器在編譯過程中使用常指針作為引用的內(nèi)部實(shí)現(xiàn),因此引用所占用的空間大小與指針相同; 3、從使用的角度,引用會(huì)讓人誤認(rèn)為其只是一個(gè)別名,沒有自己的內(nèi)存空間(跟目標(biāo)公用一個(gè)內(nèi)存空間),這是C++為了實(shí)用性而做出的細(xì)節(jié)隱藏,就是說C++不想讓人們找到引用自己真實(shí)的地址,即使你去取引用變量b的地址,也只是目標(biāo)變量a的地址。 想下指針變量具有一個(gè)地址,指針指向的空間也有一個(gè)地址,沒有隱藏,很多指針指向同一個(gè)對(duì)象時(shí),如果一個(gè)指針對(duì)對(duì)象進(jìn)行了析構(gòu),就會(huì)使其他指針變成“野指針”,這就很危險(xiǎn)!(該點(diǎn)根據(jù)自己理解,不當(dāng)之處請(qǐng)指正!)
看這兩個(gè)函數(shù): void func(int &a) //函數(shù)一 { a=5; } void func(int *const a) //函數(shù)二 { *a=5 } 當(dāng)執(zhí)行函數(shù)一的時(shí)候,是C++編譯器在背后在背后通過函數(shù)二的方式進(jìn)行了編譯。在編譯時(shí)C++看到a是一個(gè)引用,就會(huì)翻譯成函數(shù)二的形式。再看下面的程序: #include <iostream> using namespace std;
int modifyA(int &a1) { a1=100; } int modifyA2(int *a1) { *a1=200;//【*實(shí)參的地址】間接修改實(shí)參的值 } int main() { int a=10;
//指向這個(gè)函數(shù)調(diào)用的時(shí)候,我們程序員不需要取a得地址 modifyA(a); cout<<"a="<<a<<endl;
//如果是指針,需要我們程序員手工的取實(shí)參的地址 modifyA2(&a); cout<<"a="<<a<<endl;
system("pause"); return 0; }
當(dāng)我們執(zhí)行函數(shù)modifyA的時(shí)候,是C++編譯器自動(dòng)的取了a的地址傳遞給了a1。執(zhí)行modifyA函數(shù)調(diào)用的時(shí)候,我們就不需要再取a的地址了,C++編譯器幫我們取了。如果是執(zhí)行modifyA2函數(shù),使用指針,就需要傳遞a的地址。 第四,引用小結(jié)先來看間接賦值成立的三個(gè)條件: 1、定義兩個(gè)變量(一個(gè)實(shí)參一個(gè)形參) 2、建立關(guān)聯(lián),實(shí)參取地址傳給形參 3、*p形參去間接修改實(shí)參的值 小結(jié): 1、引用在實(shí)現(xiàn)上,只不過是把間接賦值成立的三個(gè)條件的后兩步合二為一。當(dāng)實(shí)參傳給形參引用的時(shí)候,只不過是C++編譯器幫我們程序員自動(dòng)取了一個(gè)實(shí)參地址,傳給了形參引用(常量指針)。 2、當(dāng)我們使用引用語法時(shí),我們不去關(guān)心編譯器引用是怎么做的。當(dāng)我們分析奇怪的語法現(xiàn)象時(shí),我們才去考慮C++編譯器是怎么做的。
【C++】筆記系列均為原創(chuàng),轉(zhuǎn)載請(qǐng)注明轉(zhuǎn)自微號(hào):依法編程 更多精彩資料,請(qǐng)關(guān)注!
|