解析C++引用
引言
我選擇寫C++中的引用是因為我感覺大多數(shù)人誤解了引用。而我之所以有這個感受是因為我主持過很多C++的面試,并且我很少從面試者中得到關(guān)于C++引用的正確答案。
那么c++中引用到底意味這什么呢?通常一個引用讓人想到是一個引用的變量的別名,而我討厭將c++中引用定義為變量的別名。這篇文章中,我將盡量解釋清楚,c++中根本就沒有什么叫做別名的東東。
背景
在c/c++中,訪問一個變量只能通過兩種方式被訪問,傳遞,或者查詢。這兩種方式是:
1.通過值訪問/傳遞變量
2.通過地址訪問/傳遞變量–這種方法就是指針
除此之外沒有第三種訪問和傳遞變量值的方法。引用變量也就是個指針變量,它也擁有內(nèi)存空間。最關(guān)鍵的是引用是一種會被編譯器自動解引用的指針。很難相信么?
下面是一段使用引用的簡單c++代碼
#include <iostream.h> int main() { int i = 10; // A simple integer variable int &j = i; // A Reference to the variable i j++; // Incrementing j will increment both i and j. // check by printing values of i and j cout<< i << j <<endl; // should print 11 11 // Now try to print the address of both variables i and j cout<< &i << &j <<endl; // surprisingly both print the same address and make us feel that they are // alias to the same memory location. // In example below we will see what is the reality return 0; }
引用其實就是c++中的常量指針。表達(dá)式int &i = j;將會被編譯器轉(zhuǎn)化成int *const i = &j;而引用之所以要初始化是因為const類型變量必須初始化,這個指針也必須有所指。下面我們再次聚焦到上面這段代碼,并使用編譯器的那套語法將引用替換掉。
#include <iostream.h> int main() { int i = 10; // A simple integer variable int *const j = &i; // A Reference to the variable i (*j)++; // Incrementing j. Since reference variables are // automatically dereferenced by compiler // check by printing values of i and j cout<< i << *j <<endl; // should print 11 11 // A * is appended before j because it used to be reference variable // and it should get automatically dereferenced. return 0; }
讀者一定很奇怪為什么我上面這段代碼會跳過打印地址這步。這里需要一些解釋。因為引用變量時會被編譯器自動解引用的,那么一個諸如cout << &j << endl;的語句,編譯器就會將其轉(zhuǎn)化成語句cout << &*j << endl;現(xiàn)在&*會相互抵消,這句話變的毫無意義,而cout打印的j值就是i的地址,因為其定義語句為int *const j = &i;
所以語句cout << &i << &j << endl;變成了cout << &i << &*j << endl;這兩種情況都是打印輸出i的地址。這就是當(dāng)我們打印普通變量和引用變量的時候會輸出相同地址的原因。
下面給出一段復(fù)雜一些的代碼,來看看引用在級聯(lián)(cascading)中是如何運作的。
#include <iostream.h> int main() { int i = 10; // A Simple Integer variable int &j = i; // A Reference to the variable // Now we can also create a reference to reference variable. int &k = j; // A reference to a reference variable // Similarly we can also create another reference to the reference variable k int &l = k; // A reference to a reference to a reference variable. // Now if we increment any one of them the effect will be visible on all the // variables. // First print original values // The print should be 10,10,10,10 cout<< i << "," << j << "," << k << "," << l <<endl; // increment variable j j++; // The print should be 11,11,11,11 cout<< i << "," << j << "," << k << "," << l <<endl; // increment variable k k++; // The print should be 12,12,12,12 cout<< i << "," << j << "," << k << "," << l <<endl; // increment variable l l++; // The print should be 13,13,13,13 cout<< i << "," << j << "," << k << "," << l <<endl; return 0; }
下面這段代碼是將上面代碼中的引用替換之后代碼,也就是說明我們不依賴編譯器的自動替換功能,手動進(jìn)行替換也能達(dá)到相同的目標(biāo)。
#include <iostream.h> int main() { int i = 10; // A Simple Integer variable int *const j = &i; // A Reference to the variable // The variable j will hold the address of i // Now we can also create a reference to reference variable. int *const k = &*j; // A reference to a reference variable // The variable k will also hold the address of i because j // is a reference variable and // it gets auto dereferenced. After & and * cancels each other // k will hold the value of // j which it nothing but address of i // Similarly we can also create another reference to the reference variable k int *const l = &*k; // A reference to a reference to a reference variable. // The variable l will also hold address of i because k holds address of i after // & and * cancels each other. // so we have seen that all the reference variable will actually holds the same // variable address. // Now if we increment any one of them the effect will be visible on all the // variables. // First print original values. The reference variables will have * prefixed because // these variables gets automatically dereferenced. // The print should be 10,10,10,10 cout<< i << "," << *j << "," << *k << "," << *l <<endl; // increment variable j (*j)++; // The print should be 11,11,11,11 cout<< i << "," << *j << "," << *k << "," << *l <<endl; // increment variable k (*k)++; // The print should be 12,12,12,12 cout<< i << "," << *j << "," << *k << "," << *l <<endl; // increment variable l (*l)++; // The print should be 13,13,13,13 cout << i << "," << *j << "," << *k << "," << *l <<endl; return 0; }
我們通過下面代碼可以證明c++的引用不是神馬別名,它也會占用內(nèi)存空間的。
#include <iostream.h> class Test { int &i; // int *const i; int &j; // int *const j; int &k; // int *const k; }; int main() { // This will print 12 i.e. size of 3 pointers cout<< "size of class Test = " << sizeof(class Test) <<endl; return 0; }
結(jié)論
我希望這篇文章能把c++引用的所有東東都解釋清楚,然而我要指出的是c++標(biāo)準(zhǔn)并沒有解釋編譯器如何實現(xiàn)引用的行為。所以實現(xiàn)取決于編譯器,而大多數(shù)情況下就是將引用實現(xiàn)為一個const指針。
引用支持c++虛函數(shù)機(jī)制的代碼
#include <iostream.h> class A { public: virtual void print() { cout<<"A.."<<endl; } }; class B : public A { public: virtual void print() { cout<<"B.."<<endl; } }; class C : public B { public: virtual void print() { cout<<"C.."<<endl; } }; int main() { C c1; A &a1 = c1; a1.print(); // prints C A a2 = c1; a2.print(); // prints A return 0; }
上述代碼使用引用支持虛函數(shù)機(jī)制。如果引用僅僅是一個別名,那如何實現(xiàn)虛函數(shù)機(jī)制,而虛函數(shù)機(jī)制所需要的動態(tài)信息只能通過指針才能實現(xiàn),所以更加說明引用其實就是一個const指針。
以上就是解析C++引用的詳細(xì)內(nèi)容,更多關(guān)于C++引用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C/C++實現(xiàn)發(fā)送與接收HTTP/S請求的示例代碼
HTTP(Hypertext Transfer Protocol)是一種用于傳輸超文本的協(xié)議,它是一種無狀態(tài)的、應(yīng)用層的協(xié)議,用于在計算機(jī)之間傳輸超文本文檔,通常在 Web 瀏覽器和 Web 服務(wù)器之間進(jìn)行數(shù)據(jù)通信,本文給大家介紹了C/C++發(fā)送與接收HTTP/S請求,需要的朋友可以參考下2023-11-11