C++引用(作為函式引數和返回值)
阿新 • • 發佈:2019-02-15
一、引用簡介
引用就是某一變數(目標)的一個別名,對引用的操作與對變數直接操作完全一樣。
引用的宣告方法:型別識別符號 &引用名=目標變數名;
eg:int a; int &b=a; //定義引用b,它是變數a的引用,即別名
說明:
(1)&在此不是求地址運算,而是起標識作用。
(2)型別識別符號是指目標變數的型別。
(3)宣告引用時,必須同時對其進行初始化。
(4)引用宣告完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,且不能再把該引用名作為其他變數名的別名。 b=1; 等價於 a=1;
(5)宣告一個引用,不是新定義了一個變數,它只表示該引用名是目標變數名的一個別名,它本身不是一種資料型別,因此引用本身不佔儲存單元,系統也不給引用分配儲存單元。故:對引用求地址,就是對目標變數求地址。&ra與&a相等。
(6)不能建立陣列的引用。因為陣列是一個由若干個元素所組成的集合,所以無法建立一個數組的別名。
C++ 引用 vs 指標
引用很容易與指標混淆,它們之間有三個主要的不同:
執行結果:
三、把引用作為函式返回值 引用作為返回值,必須遵守以下規則: (1)不能返回區域性變數的引用。主要原因是區域性變數會在函式返回後被銷燬,因此被返回的引用就成為了"無所指"的引用,程式會進入未知狀態。 (2)不能返回函式內部new分配的記憶體的引用。例如,對於返回函式內部new分配記憶體的引用,被函式返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變數,那麼這個引用所指向的空間(由new分配)就無法釋放,造成memory leak。 (3)可以返回類成員的引用,但最好是const。主要原因是當物件的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者物件的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它物件可以獲得該屬性的非常量引用(或指標),那麼對該屬性的單純賦值就會破壞業務規則的完整性。
(4)引用與一些操作符的過載。流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout
<< "hello" << endl; 因此這兩個操作符的返回值應該是一個仍然支援這兩個操作符的流引用。
(5)在另外的一些操作符中,卻千萬不能返回引用:+-*/
四則運算子。它們不能返回引用。主要原因是這四個操作符沒有side effect,因此,它們必須構造一個物件作為返回值,可選的方案包括:返回一個物件、返回一個區域性變數的引用,返回一個new分配的物件的引用、返回一 個靜態物件引用。根據前面提到的引用作為返回值的三個規則,第2、3兩個方案都被否決了。靜態物件的引用又因為((a+b) == (c+d))會永遠為true而導致錯誤。所以可選的只剩下返回一個物件了。
執行效果:
四、常引用 常引用宣告方式:const 型別識別符號 &引用名=目標變數名; 用這種方式宣告的引用,不能通過引用對目標變數的值進行修改,從而使引用的目標成為const,達到了引用的安全性。 int a ; const int &b=a; b=1; //錯誤 a=1; //正確 五、引用和多型 引用是除指標外另一個可以產生多型效果的手段。這意味著,一個基類的引用可以指向它的派生類例項。 class A; class B:public A{……}; B b; A &Ref = b; // 用派生類物件初始化基類物件的引用 Ref 只能用來訪問派生類物件中從基類繼承下來的成員,是基類引用指向派生類。如果A類中定義有虛擬函式,並且在B類中重寫了這個虛擬函式,就可以通過Ref產生多型效果。 六、引用總結 (1)在引用的使用中,單純給某個變數取個別名是毫無意義的,引用的目的主要用於在函式引數傳遞中,解決大塊資料或物件的傳遞效率和空間不如意的問題。 (2)用引用傳遞函式的引數,能保證引數傳遞中不產生副本,提高傳遞的效率,且通過const的使用,保證了引用傳遞的安全性。 (3)引用與指標的區別是,指標通過某個指標變數指向一個物件後,對它所指向的變數間接操作。程式中使用指標,程式的可讀性差;而引用本身就是目標變數的別名,對引用的操作就是對目標變數的操作。 (4)使用引用的時機。流操作符<<和>>、賦值操作符=的返回值、拷貝建構函式的引數、賦值操作符=的引數、其它情況都推薦使用引用。
- 不存在空引用。引用必須連線到一塊合法的記憶體。
- 一旦引用被初始化為一個物件,就不能被指向到另一個物件。指標可以在任何時候指向到另一個物件。
- 引用必須在建立時被初始化。指標可以在任何時間被初始化。
//把引用作為引數 void swap ( int& x,int& y ){ int temp; temp=x; x=y; y=temp; } int main(){ int a=100,b=200; cout<<"交換之前,a:"<<a<<",b:"<<b<<endl; swap(a,b); cout<<"交換之後,a:"<<a<<",b:"<<b<<endl; return 0; }
執行結果:
三、把引用作為函式返回值 引用作為返回值,必須遵守以下規則: (1)不能返回區域性變數的引用。主要原因是區域性變數會在函式返回後被銷燬,因此被返回的引用就成為了"無所指"的引用,程式會進入未知狀態。 (2)不能返回函式內部new分配的記憶體的引用。例如,對於返回函式內部new分配記憶體的引用,被函式返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變數,那麼這個引用所指向的空間(由new分配)就無法釋放,造成memory leak。 (3)可以返回類成員的引用,但最好是const。主要原因是當物件的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者物件的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它物件可以獲得該屬性的非常量引用(或指標),那麼對該屬性的單純賦值就會破壞業務規則的完整性。
//把引用作為返回值
double arrs[5]={12.94,23.56,12.0,9.43,45.63};
double& setValues(int i){
return arrs[i];
}
int main(){
cout<<"改變前的值:"<<endl;
for (int i = 0; i < 5; i++)
{
cout<<"arrs["<<i<<"]:"<<arrs[i]<<endl;
}
//改變其中的兩個元素
setValues(1)=11.11;
setValues(3)=33.33;
cout<<"改變後的值:"<<endl;
for (int i = 0; i < 5; i++)
{
cout<<"arrs["<<i<<"]:"<<arrs[i]<<endl;
}
}
執行效果:
四、常引用 常引用宣告方式:const 型別識別符號 &引用名=目標變數名; 用這種方式宣告的引用,不能通過引用對目標變數的值進行修改,從而使引用的目標成為const,達到了引用的安全性。 int a ; const int &b=a; b=1; //錯誤 a=1; //正確 五、引用和多型 引用是除指標外另一個可以產生多型效果的手段。這意味著,一個基類的引用可以指向它的派生類例項。 class A; class B:public A{……}; B b; A &Ref = b; // 用派生類物件初始化基類物件的引用 Ref 只能用來訪問派生類物件中從基類繼承下來的成員,是基類引用指向派生類。如果A類中定義有虛擬函式,並且在B類中重寫了這個虛擬函式,就可以通過Ref產生多型效果。 六、引用總結 (1)在引用的使用中,單純給某個變數取個別名是毫無意義的,引用的目的主要用於在函式引數傳遞中,解決大塊資料或物件的傳遞效率和空間不如意的問題。 (2)用引用傳遞函式的引數,能保證引數傳遞中不產生副本,提高傳遞的效率,且通過const的使用,保證了引用傳遞的安全性。 (3)引用與指標的區別是,指標通過某個指標變數指向一個物件後,對它所指向的變數間接操作。程式中使用指標,程式的可讀性差;而引用本身就是目標變數的別名,對引用的操作就是對目標變數的操作。 (4)使用引用的時機。流操作符<<和>>、賦值操作符=的返回值、拷貝建構函式的引數、賦值操作符=的引數、其它情況都推薦使用引用。