前言:引用是C++一個很重要的特性,,最近看了很多有關(guān)引用的資料和博客,故在此對引用的相關(guān)知識進行總結(jié) 一,、什么是引用引用,,顧名思義是某一個變量或?qū)ο蟮?span style="font-size: 16px">別名,對引用的操作與對其所綁定的變量或?qū)ο蟮牟僮魍耆葍r 語法:類型 &引用名=目標變量名,;
特別注意: 1.&不是求地址運算符,,而是起標志作用 2.引用的類型必須和其所綁定的變量的類型相同 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 double a=10.3; 5 int &b=a; //錯誤,引用的類型必須和其所綁定的變量的類型相同 6 cout<<b<<endl; 7 } 3.聲明引用的同時必須對其初始化,,否則系統(tǒng)會報錯 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int &a; //錯誤,!聲明引用的同時必須對其初始化 5 return 0; 6 } 4.引用相當于變量或?qū)ο蟮膭e名,,因此不能再將已有的引用名作為其他變量或?qū)ο蟮拿只騽e名 5.引用不是定義一個新的變量或?qū)ο螅虼?strong>內(nèi)存不會為引用開辟新的空間存儲這個引用 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int value=10; 5 int &new_value=value; 6 cout<<"value在內(nèi)存中的地址為:"<<&value<<endl; 7 cout<<"new_value在內(nèi)存中的地址為:"<<&new_value<<endl; 8 return 0; 9 } 6.對數(shù)組的引用 語法:類型 (&引用名)[數(shù)組中元素數(shù)量]=數(shù)組名,;
1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int a[3]={1,2,3}; 5 int (&b)[3]=a;//對數(shù)組的引用 6 cout<<&a[0]<<" "<<&b[0]<<endl; 7 cout<<&a[1]<<" "<<&b[1]<<endl; 8 cout<<&a[2]<<" "<<&b[2]<<endl; 9 return 0; 10 } 7.對指針的引用 語法:類型 *&引用名=指針名;//可以理解為:(類型*) &引用名=指針名,,即將指針的類型當成類型* 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int a=10; 5 int *ptr=&a; 6 int *&new_ptr=ptr; 7 cout<<&ptr<<" "<<&new_ptr<<endl; 8 return 0; 9 }
二、引用的應(yīng)用A.引用作為函數(shù)的參數(shù)1 #include<iostream> 2 using namespace std; 3 void swap(int &a,int &b){//引用作為函數(shù)的參數(shù) 4 int temp=a; 5 a=b; 6 b=temp; 7 } 8 int main(){ 9 int value1=10,value2=20; 10 cout<<"----------------------交換前----------------------------"<<endl; 11 cout<<"value1的值為:"<<value1<<endl; 12 cout<<"value2的值為:"<<value2<<endl; 13 swap(value1,value2); 14 cout<<"----------------------交換后----------------------------"<<endl; 15 cout<<"value1的值為:"<<value1<<endl; 16 cout<<"value2的值為:"<<value2<<endl; 17 return 0; 18 } 特別注意: 1.當用引用作為函數(shù)的參數(shù)時,,其效果和用指針作為函數(shù)參數(shù)的效果相當,。當調(diào)用函數(shù)時,函數(shù)中的形參就會被當成實參變量或?qū)ο蟮囊粋€別名來使用,,也就是說此時函數(shù)中對形參的各種操作實際上是對實參本身進行操作,,而非簡單的將實參變量或?qū)ο蟮闹悼截惤o形參。 2.通常函數(shù)調(diào)用時,,系統(tǒng)采用值傳遞的方式將實參變量的值傳遞給函數(shù)的形參變量,。此時,系統(tǒng)會在內(nèi)存中開辟空間用來存儲形參變量,,并將實參變量的值拷貝給形參變量,,也就是說形參變量只是實參變量的副本而已;并且如果函數(shù)傳遞的是類的對象,,系統(tǒng)還會調(diào)用類中的拷貝構(gòu)造函數(shù)來構(gòu)造形參對象,。而使用引用作為函數(shù)的形參時,由于此時形參只是要傳遞給函數(shù)的實參變量或?qū)ο蟮膭e名而非副本,,故系統(tǒng)不會耗費時間來在內(nèi)存中開辟空間來存儲形參,。因此如果參數(shù)傳遞的數(shù)據(jù)較大時,建議使用引用作為函數(shù)的形參,,這樣會提高函數(shù)的時間效率,,并節(jié)省內(nèi)存空間。 3.使用指針作為函數(shù)的形參雖然達到的效果和使用引用一樣,,但當調(diào)用函數(shù)時仍需要為形參指針變量在內(nèi)存中分配空間,,而引用則不需要這樣,故在C++中推薦使用引用而非指針作為函數(shù)的參數(shù) 4.如果在編程過程中既希望通過讓引用作為函數(shù)的參數(shù)來提高函數(shù)的編程效率,,又希望保護傳遞的參數(shù)使其在函數(shù)中不被改變,,則此時應(yīng)當使用對常量的引用作為函數(shù)的參數(shù)。 5.數(shù)組的引用作為函數(shù)的參數(shù):C++的數(shù)組類型是帶有長度信息的,,引用傳遞時如果指明的是數(shù)組則必須指定數(shù)組的長度 1 #include<iostream> 2 using namespace std; 3 void func(int(&a)[5]){//數(shù)組引用作為函數(shù)的參數(shù),,必須指明數(shù)組的長度 4 //函數(shù)體 5 } 6 int main(){ 7 int number[5]={0,1,2,3,4}; 8 func(number); 9 return 0; 10 } B.常引用語法:const 類型 &引用名=目標變量名;
常引用不允許通過該引用對其所綁定的變量或?qū)ο筮M行修改 1 #include<iostream> 2 using namespace std; 3 int main(){ 4 int a=10; 5 const int &new_a=a; 6 new_a=11;//錯誤,!不允許通過常引用對其所綁定的變量或?qū)ο筮M行修改 7 return 0; 8 } 特別注意: 先看下面的例子 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 string func1(){ 5 string temp="This is func1"; 6 return temp; 7 } 8 void func2(string &str){ 9 cout<<str<<endl; 10 } 11 int main(){ 12 func2(func1()); 13 func2("Tomwenxing"); 14 return 0; 15 } 運行上面的程序編譯器會報錯 這是由于func1()和“Tomwenxing”都會在系統(tǒng)中產(chǎn)生一個臨時對象(string對象)來存儲它們,,而在C++中所有的臨時對象都是const類型的,而上面的程序試圖將const對象賦值給非const對象,這必然會使程序報錯,。如果在函數(shù)func2的參數(shù)前添加const,則程序便可正常運行了 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 string func1(){ 5 string temp="This is func1"; 6 return temp; 7 } 8 void func2(const string &str){ 9 cout<<str<<endl; 10 } 11 int main(){ 12 func2(func1()); 13 func2("Tomwenxing"); 14 return 0; 15 } C.引用作為函數(shù)的返回值語法:類型 &函數(shù)名(形參列表){ 函數(shù)體 }
特別注意: 1.引用作為函數(shù)的返回值時,,必須在定義函數(shù)時在函數(shù)名前將& 2.用引用作函數(shù)的返回值的最大的好處是在內(nèi)存中不產(chǎn)生返回值的副本 1 //代碼來源:RUNOOB 2 #include<iostream> 3 using namespace std; 4 float temp; 5 float fn1(float r){ 6 temp=r*r*3.14; 7 return temp; 8 } 9 float &fn2(float r){ //&說明返回的是temp的引用,,換句話說就是返回temp本身 10 temp=r*r*3.14; 11 return temp; 12 } 13 int main(){ 14 float a=fn1(5.0); //case 1:返回值 15 //float &b=fn1(5.0); //case 2:用函數(shù)的返回值作為引用的初始化值 [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float' 上例中4個case的說明解釋: case 1:用返回值方式調(diào)用函數(shù)(如下圖,,圖片來源:伯樂在線): 返回全局變量temp的值時,,C++會在內(nèi)存中創(chuàng)建臨時變量并將temp的值拷貝給該臨時變量。當返回到主函數(shù)main后,,賦值語句a=fn1(5.0)會把臨時變量的值再拷貝給變量a case 2:用函數(shù)的返回值初始化引用的方式調(diào)用函數(shù)(如下圖,,圖片來源:伯樂在線) 這種情況下,函數(shù)fn1()是以值方式返回到,,返回時,,首先拷貝temp的值給臨時變量。返回到主函數(shù)后,,用臨時變量來初始化引用變量b,,使得b成為該臨時變量到的別名。由于臨時變量的作用域短暫(在C++標準中,,臨時變量或?qū)ο蟮纳芷谠谝粋€完整的語句表達式結(jié)束后便宣告結(jié)束,,也就是在語句float &b=fn1(5.0);之后) ,所以b面臨無效的危險,,很有可能以后的值是個無法確定的值,。 如果真的希望用函數(shù)的返回值來初始化一個引用,應(yīng)當先創(chuàng)建一個變量,,將函數(shù)的返回值賦給這個變量,,然后再用該變量來初始化引用: 1 int x=fn1(5.0); 2 int &b=x; case 3:用返回引用的方式調(diào)用函數(shù)(如下圖,圖片來源:伯樂在線) 這種情況下,,函數(shù)fn2()的返回值不產(chǎn)生副本,,而是直接將變量temp返回給主函數(shù),即主函數(shù)的賦值語句中的左值是直接從變量temp中拷貝而來(也就是說c只是變量temp的一個拷貝而非別名) ,,這樣就避免了臨時變量的產(chǎn)生,。尤其當變量temp是一個用戶自定義的類的對象時,這樣還避免了調(diào)用類中的拷貝構(gòu)造函數(shù)在內(nèi)存中創(chuàng)建臨時對象的過程,,提高了程序的時間和空間的使用效率,。 case 4:用函數(shù)返回的引用作為新引用的初始化值的方式來調(diào)用函數(shù)(如下圖,圖片來源:伯樂在線) 這種情況下,,函數(shù)fn2()的返回值不產(chǎn)生副本,,而是直接將變量temp返回給主函數(shù)。在主函數(shù)中,一個引用聲明d用該返回值初始化,,也就是說此時d成為變量temp的別名,。由于temp是全局變量,所以在d的有效期內(nèi)temp始終保持有效,,故這種做法是安全的,。 3.不能返回局部變量的引用。如上面的例子,,如果temp是局部變量,,那么它會在函數(shù)返回后被銷毀,此時對temp的引用就會成為“無所指”的引用,,程序會進入未知狀態(tài),。 4.不能返回函數(shù)內(nèi)部通過new分配的內(nèi)存的引用。雖然不存在局部變量的被動銷毀問題,,但如果被返回的函數(shù)的引用只是作為一個臨時變量出現(xiàn),,而沒有將其賦值給一個實際的變量,那么就可能造成這個引用所指向的空間(有new分配)無法釋放的情況(由于沒有具體的變量名,,故無法用delete手動釋放該內(nèi)存),,從而造成內(nèi)存泄漏。因此應(yīng)當避免這種情況的發(fā)生 5當返回類成員的引用時,,最好是const引用,。這樣可以避免在無意的情況下破壞該類的成員。 6.可以用函數(shù)返回的引用作為賦值表達式中的左值 1 #include<iostream> 2 using namespace std; 3 int value[10]; 4 int error=-1; 5 int &func(int n){ 6 if(n>=0&&n<=9) 7 return value[n];//返回的引用所綁定的變量一定是全局變量,,不能是函數(shù)中定義的局部變量 8 else 9 return error; 10 } 11 12 int main(){ 13 func(0)=10; 14 func(4)=12; 15 cout<<value[0]<<endl; 16 cout<<value[4]<<endl; 17 return 0; 18 } D.用引用實現(xiàn)多態(tài)在C++中,,引用是除了指針外另一個可以產(chǎn)生多態(tài)效果的手段。也就是說一個基類的引用可以用來綁定其派生類的實例 class Father;//基類(父類) class Son:public Father{.....}//Son是Father的派生類 Son son;//son是類Son的一個實例 Father &ptr=son;//用派生類的對象初始化基類對象的使用 特別注意: ptr只能用來訪問派生類對象中從基類繼承下來的成員,。如果基類(類Father)中定義的有虛函數(shù),,那么就可以通過在派生類(類Son)中重寫這個虛函數(shù)來實現(xiàn)類的多態(tài)。
三,、總結(jié)1.在引用的使用中,,單純給某個變量去別名是毫無意義的,引用的目的主要用于在函數(shù)參數(shù)的傳遞中,,解決大塊數(shù)據(jù)或?qū)ο蟮膫鬟f效率和空間不如意的問題 2.用引用傳遞函數(shù)的參數(shù),,能保證參數(shù)在傳遞的過程中不產(chǎn)生副本,從而提高傳遞效率,,同時通過const的使用,,還可以保證參數(shù)在傳遞過程中的安全性 3.引用本身是目標變量或?qū)ο蟮膭e名,對引用的操作本質(zhì)上就是對目標變量或?qū)ο蟮牟僮?。因?strong>能使用引用時盡量使用引用而非指針
|
|