C++深入探究引用的本質(zhì)與意義
一、引用的意義
- 引用作為變量別名而存在,因此在一些場(chǎng)合可以代替指針
- 引用相對(duì)于指針來(lái)說(shuō)具有更好的可讀性和實(shí)用性
下面通過(guò)代碼來(lái)進(jìn)行說(shuō)明,在C語(yǔ)言中,可以這么寫:
#include <stdio.h> void swap(int* a, int* b) { int t = *a; *a = *b; *b = t; } int main() { int a = 1; int b = 2; swap(&a, &b); printf("a = %d, b = %d\n", a, b); return 0; }
下面為輸出結(jié)果,可以看到a,b被交換。
若采用C++用的引用,則采用下面的代碼:
#include <stdio.h> void swap(int& a, int& b) { int t = a; a = b; b = t; } int main() { int a = 1; int b = 2; swap(a, b); printf("a = %d, b = %d\n", a, b); return 0; }
下面為輸出結(jié)果,需要注意的是,引用作為函數(shù)的形參時(shí),不需要進(jìn)行初始化,初始化發(fā)生在函數(shù)調(diào)用的時(shí)候(形參一旦被初始化后,就代表兩個(gè)具體的外部變量)。
二、特殊的引用
const 引用
- 在C++中可以聲明const 引用
- const Type& name = var ;
- const 引用讓變量擁有只讀屬性
- 當(dāng)使用常量對(duì)const引用進(jìn)行初始化時(shí),C++編譯器會(huì)為常量值分配空間,并將引用名作為這段空間的別名
所以上面那段代碼,b = 5 是不正確的,因?yàn)?b 已經(jīng)是只讀變量了,但是依舊可以通過(guò)指針改變這個(gè)只讀變量的值。
結(jié)論:使用常量對(duì)const 引用初始化后將生成一個(gè)只讀變量
下面看一段代碼,加深理解:
#include <stdio.h> void Example() { printf("Example:\n"); int a = 4; const int& b = a; int* p = (int*)&b; //b = 5; *p = 5; printf("a = %d\n", a); printf("b = %d\n", b); } void Demo() { printf("Demo:\n"); const int& c = 1; int* p = (int*)&c; //c = 5; *p = 5; printf("c = %d\n", c); } int main(int argc, char *argv[]) { Example(); printf("\n"); Demo(); return 0; }
下面為輸出結(jié)果:
如果把那兩行(b = 5,c = 5)取消注釋,則就會(huì)輸出下面結(jié)果,編譯器會(huì)報(bào) b 和 c 都是只讀變量的錯(cuò)誤。
三、引用是否占用存儲(chǔ)空間
下面看一段代碼:
#include <stdio.h> struct TRef { char& r; }; int main(int argc, char *argv[]) { char c = 'c'; char& rc = c; TRef ref = { c }; printf("sizeof(char&) = %d\n", sizeof(char&)); //char類型占用一個(gè)字節(jié) 1 printf("sizeof(rc) = %d\n", sizeof(rc)); //sizeof(c) => 1 printf("sizeof(TRef) = %d\n", sizeof(TRef)); //? printf("sizeof(ref.r) = %d\n", sizeof(ref.r)); //sizeof(c) => 1 return 0; }
下面為輸出結(jié)果,可以看到sizeof(TRef)占用的內(nèi)存空間為4,我們知道指針占用的內(nèi)存空間為4,那么指針和引用到底有什么關(guān)系呢?第4節(jié)來(lái)分析。
四、引用的本質(zhì)
引用在C++中的內(nèi)部實(shí)現(xiàn)是一個(gè)指針常量
注意:
- C++編譯器在編譯過(guò)程中用指針常量作為引用的內(nèi)部實(shí)現(xiàn),因此引用所占用的空間大小與指針相同。
- 從使用的角度,引用只是一個(gè)別名,C++為了實(shí)用性而隱藏了引用的存儲(chǔ)空間這一細(xì)節(jié)。
通過(guò)下面的代碼,也可以很好的理解引用所占的字節(jié)數(shù):
#include <stdio.h> struct TRef { char* before; char& ref; char* after; }; int main(int argc, char* argv[]) { char a = 'a'; char& b = a; char c = 'c'; TRef r = {&a, b, &c}; printf("sizeof(r) = %d\n", sizeof(r)); printf("sizeof(r.before) = %d\n", sizeof(r.before)); printf("sizeof(r.after) = %d\n", sizeof(r.after)); printf("&r.before = %p\n", &r.before); printf("&r.after = %p\n", &r.after); return 0; }
下面為輸出結(jié)果,可以看到結(jié)構(gòu)體占用12個(gè)字節(jié),before 和 after 指針各占用4個(gè)字節(jié),所以 ref 引用當(dāng)然也占用4個(gè)字節(jié),通過(guò) after 的起始內(nèi)存地址減上 before 的起始內(nèi)存地址得8,而 before 指針占用4個(gè)字節(jié),從這個(gè)層面也能知道 ref 引用占用4個(gè)字節(jié)。
為了深入理解引用的本質(zhì),可以在 Visual Studio 2012 中進(jìn)行反匯編,如下圖,現(xiàn)在return 0那里打個(gè)斷點(diǎn),然后點(diǎn)擊本地 Windows 調(diào)試器,開(kāi)始執(zhí)行代碼。
執(zhí)行完代碼后,鼠標(biāo)右擊空白區(qū)域,選擇轉(zhuǎn)到反匯編。
下面看一下反匯編的部分代碼,主要看引用那部分的匯編代碼,lea eax,[a] 表示取a的地址,存到 eax 寄存器中,mov dword ptr [b],eax表示把a(bǔ) 的地址保存到 b 所對(duì)應(yīng)的4個(gè)內(nèi)存空間里面去??梢赃@么說(shuō),引用的內(nèi)部實(shí)現(xiàn)就是指針,所以引用占用內(nèi)存空間,且占用內(nèi)存空間大小和指針一樣。
五、引用的注意事項(xiàng)
C++中的引用旨在大多數(shù)的情況下代替指針
- 功能性:可以滿足多數(shù)需要使用指針的場(chǎng)合
- 安全性∶可以避開(kāi)由于指針操作不當(dāng)而帶來(lái)的內(nèi)存錯(cuò)誤
- 操作性∶簡(jiǎn)單易用,又不失功能強(qiáng)大
下面通過(guò)一個(gè)函數(shù)返回引用,介紹一下引用的注意事項(xiàng)。
#include <stdio.h> int& demo() //從內(nèi)部實(shí)現(xiàn)來(lái)看,想返回一個(gè)指針 int* const { int d = 0; printf("demo: d = %d\n", d); return d; //本質(zhì)上,相當(dāng)于 return &d } int& func() { static int s = 0; printf("func: s = %d\n", s); return s; //本質(zhì)上,相當(dāng)于 return &s } int main(int argc, char* argv[]) { int& rd = demo(); int& rs = func(); printf("\n"); printf("main: rd = %d\n", rd); printf("main: rs = %d\n", rs); printf("\n"); rd = 10; rs = 11; demo(); func(); printf("\n"); printf("main: rd = %d\n", rd); printf("main: rs = %d\n", rs); printf("\n"); return 0; }
下面為輸出結(jié)果,可以看到編譯的時(shí)候開(kāi)始發(fā)出警告說(shuō)不能返回局部變量,如果繼續(xù)運(yùn)行,可以看到 rd = 9658356,rd 為 d 的別名,按理說(shuō)應(yīng)該輸出 0 的,為什么輸出9658356 呢?這個(gè)因?yàn)?rd 所代表的的變量在 demo 函數(shù)調(diào)用返回的時(shí)候被摧毀了,其所代表的是一個(gè)不存在的變量,所以 rd 沒(méi)有意義了。
引用中必須遵守的規(guī)則:不要返回局部變量的引用。 如果局部變量是靜態(tài)的,則可以。因?yàn)殪o態(tài)局部變量的存儲(chǔ)區(qū)是全局的存儲(chǔ)區(qū),所以它的空間不會(huì)因?yàn)楹瘮?shù)的返回而被摧毀。
六、小結(jié)
- 引用作為變量別名而存在旨在代替指針
- const 引用可以使得變量具有只讀屬性
- 引用在編譯器內(nèi)部使用指針常量實(shí)現(xiàn)
- 引用的最終本質(zhì)為指針
- 引用可以盡可能的避開(kāi)內(nèi)存錯(cuò)誤
到此這篇關(guān)于C++深入探究引用的本質(zhì)與意義的文章就介紹到這了,更多相關(guān)C++引用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++通過(guò)HTTP實(shí)現(xiàn)文件上傳與下載的示例詳解
WinInet是 Microsoft Windows 操作系統(tǒng)中的一個(gè) API 集,用于提供對(duì) Internet 相關(guān)功能的支持,它包括了一系列的函數(shù),使得 Windows 應(yīng)用程序能夠進(jìn)行網(wǎng)絡(luò)通信、處理 HTTP 請(qǐng)求、FTP 操作等,本文給大家介紹了C/C++通過(guò)HTTP實(shí)現(xiàn)文件上傳與下載,需要的朋友可以參考下2023-12-12

c語(yǔ)言中實(shí)現(xiàn)數(shù)組幾個(gè)數(shù)求次大值