【轉】C/C++ 引用作為函數的返回值


轉自:https://blog.csdn.net/weixin_40539125/article/details/81410008

這篇文章寫的很好:

語法:類型 &函數名(形參列表){ 函數體 }

特別注意:

1.引用作為函數的返回值時,必須在定義函數時在函數名前將&

2.用引用作函數的返回值的最大的好處是在內存中不產生返回值的副本

  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:用函數的返回值作為引用的初始化值 [Error] invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
  16.  
    //(有些編譯器可以成功編譯該語句,但會給出一個warning)
  17.  
    float c=fn2(5.0);//case 3:返回引用
  18.  
    float &d=fn2(5.0);//case 4:用函數返回的引用作為新引用的初始化值
  19.  
    cout<<a<<endl;//78.5
  20.  
    //cout<<b<<endl;//78.5
  21.  
    cout<<c<<endl;//78.5
  22.  
    cout<<d<<endl;//78.5
  23.  
    return 0;
  24.  
    }

case 1:用返回值方式調用函數(如下圖,圖片來源:伯樂在線):

返回全局變量temp的值時,C++會在內存中創建臨時變量並將temp的值拷貝給該臨時變量。當返回到主函數main后,賦值語句a=fn1(5.0)會把臨時變量的值再拷貝給變量a

case 2:用函數的返回值初始化引用的方式調用函數(如下圖,圖片來源:伯樂在線)

這種情況下,函數fn1()是以值方式返回到,返回時,首先拷貝temp的值給臨時變量。返回到主函數后,用臨時變量來初始化引用變量b,使得b成為該臨時變量到的別名。由於臨時變量的作用域短暫(在C++標准中,臨時變量或對象的生命周期在一個完整的語句表達式結束后便宣告結束,也就是在語句float &b=fn1(5.0);之后) ,所以b面臨無效的危險,很有可能以后的值是個無法確定的值。

 如果真的希望用函數的返回值來初始化一個引用,應當先創建一個變量,將函數的返回值賦給這個變量,然后再用該變量來初始化引用:

  1.  
    int x=fn1(5.0);
  2.  
    int &b=x;

 case 3:用返回引用的方式調用函數(如下圖,圖片來源:伯樂在線)

這種情況下,函數fn2()的返回值不產生副本,而是直接將變量temp返回給主函數,即主函數的賦值語句中的左值是直接從變量temp中拷貝而來(也就是說c只是變量temp的一個拷貝而非別名) ,這樣就避免了臨時變量的產生。尤其當變量temp是一個用戶自定義的類的對象時,這樣還避免了調用類中的拷貝構造函數在內存中創建臨時對象的過程,提高了程序的時間和空間的使用效率。

case 4:用函數返回的引用作為新引用的初始化值的方式來調用函數(如下圖,圖片來源:伯樂在線)

這種情況下,函數fn2()的返回值不產生副本,而是直接將變量temp返回給主函數。在主函數中,一個引用聲明d用該返回值初始化,也就是說此時d成為變量temp的別名。由於temp是全局變量,所以在d的有效期內temp始終保持有效,故這種做法是安全的。

3.不能返回局部變量的引用。如上面的例子,如果temp是局部變量,那么它會在函數返回后被銷毀,此時對temp的引用就會成為“無所指”的引用,程序會進入未知狀態。

4.不能返回函數內部通過new分配的內存的引用。雖然不存在局部變量的被動銷毀問題,但如果被返回的函數的引用只是作為一個臨時變量出現,而沒有將其賦值給一個實際的變量,那么就可能造成這個引用所指向的空間(有new分配)無法釋放的情況(由於沒有具體的變量名,故無法用delete手動釋放該內存),從而造成內存泄漏。因此應當避免這種情況的發生

5當返回類成員的引用時,最好是const引用。這樣可以避免在無意的情況下破壞該類的成員。

6.可以用函數返回的引用作為賦值表達式中的左值

  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];//返回的引用所綁定的變量一定是全局變量,不能是函數中定義的局部變量
  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.用引用實現多態

在C++中,引用是除了指針外另一個可以產生多態效果的手段。也就是說一個基類的引用可以用來綁定其派生類的實例

  1.  
    class Father;//基類(父類)
  2.  
    class Son:public Father{.....}//Son是Father的派生類
  3.  
    Son son; //son是類Son的一個實例
  4.  
    Father &ptr=son; //用派生類的對象初始化基類對象的使用

特別注意:

ptr只能用來訪問派生類對象中從基類繼承下來的成員。如果基類(類Father)中定義的有虛函數,那么就可以通過在派生類(類Son)中重寫這個虛函數來實現類的多態。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM