c++引用總結


一、變量的引用:

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

引用的聲明方法:類型標識符 &引用名=目標變量名;

 例:char ch;

       char &rp=ch;

 1)引用僅是變量的別名,而不是實實在在地定義了一個變量,因此引用本身並不占用內存,而是和目標變量共同指向目標變量的內存地址.

 2)表達式中的取地址符&不再是取變量的地址,而是用來表示該變量是引用類型的變量。

 3)定義一個引用時,必須對其初始化。

 示例代碼:

#include <stdio.h>
#include <iostream>
using namespace std;

//c++中的引用實例
void fun(int &x){
     printf("形式參數的值為:%d\n",x);
     printf("形式參數的地址為:%d\n",&x);
     x+=10;
}
void fun2(int *num){
  printf("形式參數的值為:%d\n",*num);
  printf("形式參數的地址值為:%d\n",num); //2686724
  printf("形式參數的地址為:%d\n",&num);  //2686704 這個和
  *num =(*num)+10;

}

int main(void){
   int num = 4,a=3;

    printf("實參num的值為:%d\n",num);
    printf("實參num的地址為:%d\n",&num);//都是一樣的
    fun(num);
   cout<<"num的值為:"<<num<<endl; //14 num的值改啦

   fun2(&a);
   printf("實參a的值為:%d\n",a);
   printf("實參a的地址為:%d\n",&a);//
   return 0;
}

  

     從圖中可以看出1.引用和目標變量的地址是一樣的,對引用的修改就是對目標變量的修改。

                         2. 而后邊用指針作為函數參數,把地址傳過去,指針變量的地址是2686608,而它的值是2686696(在指針的地址上存的值),2686696這個地址指向的值是3,也就是num的值。

                         3.指針變量是有自己的值的(2686608),和num的地址(2686696)不一樣,而引用的地址是和變量的值一樣的。

二、引用的應用

1、引用作為參數

  引用的一個重要作用就是作為函數的參數。以前的C語言中函數參數傳遞是值傳遞,如果有大塊數據作為參數傳遞的時候,采用的方案往往是指針,因為這樣可以避免將整塊數據全部壓棧,可以提高程序的效率。但是現在(C++中)又增加了一種同樣有效率的選擇(在某些特殊情況下又是必須的選擇),就是引用。

     (1)使用引用傳遞函數的參數,在內存中並沒有產生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參分配存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還將調用拷貝構造函數。因此,當參數傳遞的數據較大時,用引用比用一般變量傳遞參數的效率和所占空間都好。

  (2)使用指針作為函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參分配存儲單元,且需要重復使用\"*指針變量名\"的形式進行運算,這很容易產生錯誤且程序的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的地址作為實參。而引用更容易使用,更清晰。

  如果既要利用引用提高程序的效率,又要保護傳遞給函數的數據不在函數中被改變,就應使用常引用。

     就如同上邊的例子一樣。

2、常引用

  常引用聲明方式:const  類型標識符  &引用名 = 目標變量名;

  用這種方式聲明的引用,不能通過引用對目標變量的值進行修改,從而使引用的目標成為const,達到了引用的安全性。

#include <stdio.h>
#include <iostream>
using namespace std;
void test_const();

int main(void){

   test_const();
   return 0;
}

void test_const(){
   int a=1;
     int &b=a;
     b=2;
    cout<<"a="<<a<<endl;//2
    int c=1;
    const int &d=c;
  //   d=2;//編譯錯誤 error: assignment of read_only reference 'd'
    c=2;//正確
    cout<<"c="<<c<<endl;//
}

  

     3、引用作為返回值

  要以引用返回函數值,則函數定義時要按以下格式:

    類型標識符  &函數名 (形參列表及類型說明)

    {  函數體  }

  說明:

  (1)以引用返回函數值,定義函數時需要在函數名前加&

  (2)用引用返回一個函數值的最大好處是,在內存中不產生被返回值的副本。

 以下程序中定義了一個普通的函數fn1(它用返回值的方法返回函數值),另外一個函數fn2,它以引用的方法返回函數值。

#include <iostream>
using namespace std;
 float temp;//定義全局變量temp
 float fn1(float r);//聲明函數fn1
 float &fn2(float r);//聲明函數fn2 r
 float fn1(float r){//定義函數fn1,它以返回值的方法返回函數值
    temp=(float)(r*r*3.14);
    return temp;
  }

  float &fn2(float r){//定義函數fn2,它以引用方式返回函數值
     temp=(float)(r*r*3.14);
     return temp;
 }

 int main(){
     float e=10.0;
     float a=fn1(10.0);//第1種情況,系統生成要返回值的副本(即臨時變量)
    // float &b=fn1(10.0); //第2種情況,可能會出錯(不同 C++系統有不同規定)
   /*error: invalid initialization of non-const reference of type 'float&' from an rvalue of type 'float'
   */
     //不能從被調函數中返回一個臨時變量或局部變量的引用
     float c=fn2(10.0);//第3種情況,系統不生成返回值的副本
     //可以從被調函數中返回一個全局變量的引用
     float &d=fn2(10.0); //第4種情況,系統不生成返回值的副本
     e=d;

     cout<<"a="<<a<<",c="<<c<<",d="<<d<<",e="<<e<<endl;
     //a=314,c=314,d=314
     return 0;
   }

  引用作為返回值,必須遵守以下規則:

  (1)不能返回局部變量的引用。這條可以參照Effective C++[1]的Item 31。主要原因是局部變量會在函數返回后被銷毀,因此被返回的引用就成為了"無所指"的引用,程序會進入未知狀態。如【例5】中的第2種情況出現編譯錯誤。

  (2)不能返回函數內部new分配的內存的引用。這條可以參照Effective C++[1]的Item 31。雖然不存在局部變量的被動銷毀問題,可對於這種情況(返回函數內部new分配內存的引用),又面臨其它尷尬局面。例如,被函數返回的引用只是作為一個臨時變量出現,而沒有被賦予一個實際的變量,那么這個引用所指向的空間(由new分配)就無法釋放,造成memory leak。

  (3)可以返回類成員的引用,但最好是const。這條原則可以參照Effective C++[1]的Item 30。主要原因是當對象的屬性是與某種業務規則(business rule)相關聯的時候,其賦值常常與某些其它屬性或者對象的狀態有關,因此有必要將賦值操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那么對該屬性的單純賦值就會破壞業務規則的完整性。

  (4)引用與一些操作符的重載:流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout << \"hello\" << endl; 因此這兩個操作符的返回值應該是一個仍然支持這兩個操作符的流引用。可選的其它方案包括:返回一個流對象和返回一個流對象指針。但是對於返回一個流對象,程序必須重新(拷貝)構造一個新的流對象,也就是說,連續的兩個<<操作符實際上是針對不同對象的!這無法讓人接受。對於返回一個流指針則不能連續使用<<操作符。因此,返回一個流對象引用是惟一選擇。這個唯一選擇很關鍵,它說明了引用的重要性以及無可替代性,也許這就是C++語言中引入引用這個概念的原因吧。 賦值操作符=。這個操作符象流操作符一樣,是可以連續使用的,例如:x = j = 10;或者(x=10)=100;賦值操作符的返回值必須是一個左值,以便可以被繼續賦值。因此引用成了這個操作符的惟一返回值選擇。

4、引用和多態

  引用是除指針外另一個可以產生多態效果的手段。這意味着,一個基類的引用可以指向它的派生類實例。

  【例7】:

    class  A;

    class  B:public  A{ ... ... }

    B  b;

    A  &Ref = b;//用派生類對象初始化基類對象的引用

  Ref 只能用來訪問派生類對象中從基類繼承下來的成員,是基類引用指向派生類。如果A類中定義有虛函數,並且在B類中重寫了這個虛函數,就可以通過Ref產生多態效果。

 

  引用總結

  (1)在引用的使用中,單純給某個變量取個別名是毫無意義的,引用的目的主要用於在函數參數傳遞中,解決大塊數據或對象的傳遞效率和空間不如意的問題。

  (2)用引用傳遞函數的參數,能保證參數傳遞中不產生副本,提高傳遞的效率,且通過const的使用,保證了引用傳遞的安全性。

  (3)引用與指針的區別是,指針通過某個指針變量指向一個對象后,對它所指向的變量間接操作。程序中使用指針,程序的可讀性差;而引用本身就是目標變量的別名,對引用的操作就是對目標變量的操作。

  (4)使用引用的時機。流操作符<<和>>、賦值操作符=的返回值、拷貝構造函數的參數、賦值操作符=的參數、其它情況都推薦使用引用。

        寫得真好:http://www.cnblogs.com/gw811/archive/2012/10/20/2732687.html

       保存,防止遺忘

 


免責聲明!

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



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