本帖最后由 tyyhmtyyhm 于 2018-4-28 10:02 編輯
第一,引用的意義1、引用作為其它變量的別名而存在,在一些場合可以代替指針; 2、引用相對于指針來說具有更好的可讀性和實用性。(實例可以見之前的交換兩個變量的值程序) 第二,引用的本質思考思考1:引用連接的兩個變量地址相同嗎? 之前我們理解b是a的別名,那么變量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)a和b的地址是一樣的,這說明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),轉載請注明轉自微號:依法編程 更多精彩資料,請關注!
|