C++ 學習筆記之 引用

deepwzh發表於2017-02-28

一.定義:

  引用就是某一變數(目標)的一個別名,對引用的操作與對變數直接操作完全一樣.

二.用法:

      1. 基本用法

        例如: int & a = b;

      2. 引用作為函式返回值

        先看一個例子:

         1 #include <iostream>
         2 using namespace std;
         3 class Node{
         4     int x;
         5     public:
         6     Node(const Node & n){//去掉copy函式關於h的輸出結果神奇般相同,原因未知
         7         x = n.x;
         8     }
         9     Node(int x=0):x(x){
        10 
        11     }
        12 };
        13 int temp ;
        14 int & F(){
        15     temp*=2;
        16     return temp;
        17 }
        18 int  F1(){
        19     temp*=2;
        20     return temp;
        21 }
        22 Node F2(){
        23     Node u(5);
        24     cout << &u << "  ";
        25     return u;
        26 }
        27 int main(){
        28     temp = 5;
        29     int &d = F(); //引用給引用,他們地址相同
        30     int e = F();  //引用給非引用,發生了複製
        31     const int & f = F();//把引用值賦值給常引用,他們的地址相同
        32     const int & g = F1();//對於內建資料型別,把非引用值賦值給常引用,他們的地址不同
        33     cout << &d << " " << &temp << endl;
        34     cout << &e << " " << &temp << endl;
        35     cout << &f << " " << &temp << endl;
        36     cout << &g << " " << &temp << endl;  
        37     const Node & h = F2();//對於類物件型別,把非引用值賦值給常引用,他們的地址可能不同    
        38     cout << &h << endl;     
        39     cout << d << " " << temp << endl;
        40     return 0;
        41 }
      3. 程式輸出結果為:

        0x602194 0x602194
        0x7fffe0565418 0x602194
        0x602194 0x602194
        0x7fffe056541c 0x602194
        0x7fffe0565410 0x7fffe0565410
        80 80

          從結果中可以看到,當使用引用作為程式返回值並且將這個返回值賦值給引用型別時,他們的地址是相同的(都指向temp這個變數),其他情況都產生了值的賦值,發生了地址的變化。由此也可以看出,使用引用可以減少值的複製,特別是當需要傳的資料特別大的時候。

      4.      另外,函式中返回非引用類物件賦值給const 引用變數時輸出結果有些奇怪,不明白裡面的copy函式為什麼不呼叫但只加上就可以使他們的地址相同。
      5. 常引用 基本用法如下:
        int b = 4;
        const int a = b;

        使用常引用可以是引用的值不可修改。這樣可以防止因誤操作引發的資料修改,保證了安全性。

      6. 引用函式作為左值

        一般非引用函式都是隻能作為右值,函式一旦計算完成那麼它就是一個確定的常數。但引用函式不同。它既可作為左值,又可作為右值。

        int &d = ++F();

         

        相當於

        int A[10];
        int &array = A;

         

        這是它作為左值的應用。

        但當我執行

        int &d = F()++;

        這樣會產生錯誤。錯誤資訊為:

        error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'

        這個錯誤資訊與執行

        int &d = 5;

        的錯誤資訊一致,說明F()++操作實際上是相當於先把F()的值存到一個整型常量中,然後F()(相當於temp)的值加一.一個整型常量無法複製給int&型別。

        執行

        const int &d = F()++;(使用常引用)

         

        int d = F()++;(把常量值拷貝到變數中)

        才可以正常編譯。

         

三.注意事項:

  • 引用不能用於陣列,但可以用在指標上

    如果嘗試執行

    int A[10];
    int &array = A;

     

    編譯器會報錯:
    error: declaration of 'd' as array of references

    但我可以對指標用引用:

    int *p = A;
    int &array = p;

     

    編譯成功。

    至於為什麼不能對陣列用引用,網上答案很多,我自己不能確定哪種答案是正確的,大家可以自行搜尋相關問題。

  • 不要試圖返回臨時物件的引用,這樣引用會成為無效引用,假如把返回值賦值給變數,那麼程式可能會崩掉
  • 返回函式內部new分配的記憶體的引用或指標,這樣的寫法不推薦,很容易會造成記憶體洩漏(即無法正常的回收這塊記憶體)
  • 注意常引用與普通引用之間的相互賦值問題
    1 temp = 5;
    2 const int t = 6;
    3 int &d = temp;
    4 const int &e = temp;
    5 const int &f = t;
    6 int &g = t;//編譯錯誤

    常量變數都可以賦值給常引用,但只有變數值才可以給普通引用,若常量值給普通引用會發生編譯錯誤。 

  • 另外記錄一次在寫C++作業的過程中偶然發現的一個問題,這加深了我對常引用以及ostream過載等的一些理解。點選跳轉

相關文章