您好,登錄后才能下訂單哦!
本篇內容介紹了“C++引用的本質與意義是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
引用作為變量別名而存在,因此在一些場合可以代替指針
引用相對于指針來說具有更好的可讀性和實用性
下面通過代碼來進行說明,在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; }
下面為輸出結果,可以看到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; }
下面為輸出結果,需要注意的是,引用作為函數的形參時,不需要進行初始化,初始化發生在函數調用的時候(形參一旦被初始化后,就代表兩個具體的外部變量)。
const 引用
在C++中可以聲明const 引用
const Type& name = var ;
const 引用讓變量擁有只讀屬性
當使用常量對const引用進行初始化時,C++編譯器會為常量值分配空間,并將引用名作為這段空間的別名
所以上面那段代碼,b = 5 是不正確的,因為 b 已經是只讀變量了,但是依舊可以通過指針改變這個只讀變量的值。
結論:使用常量對const 引用初始化后將生成一個只讀變量
下面看一段代碼,加深理解:
#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; }
下面為輸出結果:
如果把那兩行(b = 5,c = 5)取消注釋,則就會輸出下面結果,編譯器會報 b 和 c 都是只讀變量的錯誤。
下面看一段代碼:
#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類型占用一個字節 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; }
下面為輸出結果,可以看到sizeof(TRef)占用的內存空間為4,我們知道指針占用的內存空間為4,那么指針和引用到底有什么關系呢?第4節來分析。
引用在C++中的內部實現是一個指針常量
注意:
C++編譯器在編譯過程中用指針常量作為引用的內部實現,因此引用所占用的空間大小與指針相同。
從使用的角度,引用只是一個別名,C++為了實用性而隱藏了引用的存儲空間這一細節。
通過下面的代碼,也可以很好的理解引用所占的字節數:
#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; }
下面為輸出結果,可以看到結構體占用12個字節,before 和 after 指針各占用4個字節,所以 ref 引用當然也占用4個字節,通過 after 的起始內存地址減上 before 的起始內存地址得8,而 before 指針占用4個字節,從這個層面也能知道 ref 引用占用4個字節。
為了深入理解引用的本質,可以在 Visual Studio 2012 中進行反匯編,如下圖,現在return 0那里打個斷點,然后點擊本地 Windows 調試器,開始執行代碼。
執行完代碼后,鼠標右擊空白區域,選擇轉到反匯編。
下面看一下反匯編的部分代碼,主要看引用那部分的匯編代碼,lea eax,[a] 表示取a的地址,存到 eax 寄存器中,mov dword ptr [b],eax表示把a 的地址保存到 b 所對應的4個內存空間里面去。可以這么說,引用的內部實現就是指針,所以引用占用內存空間,且占用內存空間大小和指針一樣。
C++中的引用旨在大多數的情況下代替指針
功能性:可以滿足多數需要使用指針的場合
安全性∶可以避開由于指針操作不當而帶來的內存錯誤
操作性∶簡單易用,又不失功能強大
下面通過一個函數返回引用,介紹一下引用的注意事項。
#include <stdio.h> int& demo() //從內部實現來看,想返回一個指針 int* const { int d = 0; printf("demo: d = %d\n", d); return d; //本質上,相當于 return &d } int& func() { static int s = 0; printf("func: s = %d\n", s); return s; //本質上,相當于 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; }
下面為輸出結果,可以看到編譯的時候開始發出警告說不能返回局部變量,如果繼續運行,可以看到 rd = 9658356,rd 為 d 的別名,按理說應該輸出 0 的,為什么輸出9658356 呢?這個因為 rd 所代表的的變量在 demo 函數調用返回的時候被摧毀了,其所代表的是一個不存在的變量,所以 rd 沒有意義了。
引用中必須遵守的規則:不要返回局部變量的引用。 如果局部變量是靜態的,則可以。因為靜態局部變量的存儲區是全局的存儲區,所以它的空間不會因為函數的返回而被摧毀。
“C++引用的本質與意義是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。