天天看點

const,引用,const引用,非const引用const引用const引用const形參引用形參

const

const的出現,把一個變量轉換為一個常量,這樣就避免了變量指派在程式中由于過失而被改變,因為const是隻讀的。

1 定義const

因為常量在定義後不能被修改,是以const對象在定義時必須初始化。

const std::string s = "welcome";//正确
    const int i;//錯誤
           

2 const對象預設為檔案的局部變量

//file_1
      int i ;
    //file_2
      extern int i; //使用file_1中的i
      i++;         //非const對象在file_2中仍然可以使用
           

除非特别說明,在全局作用域聲明的const變量是定義該對象的檔案的局部變量,不能被其他檔案通路,隻存在于定義它的檔案中。

非const變量預設為extern。要使const變量能在其他檔案中使用,必須顯示地定義為extern const

//file_1
    extern const int j = ;
    //file_2
    extern const int j;//使用file_1中的j
    while(j!=)
    {...}
           

引用

1 引用隻是别名

引用隻是它綁定的對象的别名,所有在作用在引用上的操作其實都是作用在該引用綁定的對象上。

引用必須用與該引用同類型的對象初始化,且必須定義時一并初始化

int i = ,j=;
    int &k = i; //正确
    int &k; //錯誤
    int &k = ; //錯誤
    int &m = i,&n = j;//定義多個引用
    int &m = i,n = j;//m是引用,n是int
           

const引用

const引用是指向const對象的引用

1 const引用的聲明及初始化

1 能用同類型對象去初始化,且聲明時初始化

const int i = ;
    const int &j = i;//用同類型對象初始化
    int &m = i;//錯誤,m是非const引用,指向的值可修改,而i是const對象,不可修改,将普通的引用綁定到const對象是不合法的。
           

2 也能初始化為不同但相關類型*的對象或者右值(隻有const引用能這樣,非const引用依舊遵循隻能用同類型對象去初始化)

int i = ;
    const int &j = ;//合法
    const int &m = &i+j;//合法
           

綁定到不同類型時;

double i = ;
    const int &j = i;
           

編譯器會把代碼轉換為如下形式的編碼:

int temp = i;
    const int &j = temp;//僅允許const引用綁定到需要臨時變量作為媒介來完全綁定過程的值,因為const引用是隻讀的。
           

const形參

1 若函數形參為非引用非const,則既可以給該函數傳遞const實參也可以傳遞非const的實參。

int rgcd(int a,int b)
    {...}
    const int i=,j =;
    int k = rgcd(,);//合法 
           

2 若形參定義為非引用的const類型,則在函數中不可改變實參的局部副本,但由于實參仍然是以副本的形式傳遞,是以既可以傳遞const實參,也可以傳遞非const實參

int fcn(const int i)
    {...}
           

引用形參

引用形參和指針形參的出現,主要為解決複制實參的局限性

不宜複制實參的情況包括:

  • 當需要在函數中修改實參的值
  • 當需要以大型對象作為實參傳遞時。對實際應用而言,複制對象所付出的時間和存儲空間代價往往過大
  • 當沒有辦法實作對象的複制時

指針形參

形參是指針形參的,傳遞對象時是複制指針實參。如果函數是将新的指針值賦給形參,主調函數使用的實參指針的值沒有改變。

void reset(int *ip)
    {
     *ip = ;//使ip指向的對象值為
     ip = ;//僅改變ip在該函數中的值,實參并未改變
    }
    int i = ;
    int *p = &i;
    cout<<"i:"<<*p<<'\n'; //i:
    reset(p);
    cout<<"i:"<<*p<<endl;//i:
           

如果要保護指針指向的值,則形參要定義為const對象的指針

void use_ptr(const int *p)
    {
      //隻能讀取指針指向的值,而不能改變至指針指向的值
    }
           

既可以用int 也可以用const int 的實參來調用use_ptr函數,但僅能将int *類型的實參傳遞給reset函數。可以将指向const對象的指針初始化指向非const對象,但是不可以讓指向非const對象的指針指向const對象

引用形參

與所有引用一樣,引用形參直接關聯到其所綁定的對象,而并非這些對象的副本。

  • 使用引用形參傳回額外的資訊

    比如解決函數有不止一個内容需要傳回

  • 利用const引用避免複制

    如果使用引用的唯一目的是避免複制實參,則應将形參定義為const引用類型。

  • 更靈活的指向const的引用
    //函數形參為非const引用
         int incr(int &val)
         {
            return val++;
         }
         int main()
         {
            short v1 = ;
            const int v2 = ;
            int v3 = incr(v1);  //錯誤 v1不是int
            v3 = incr(v2);      //錯誤,v2是const
            v3 = incr();       //錯誤,0是常量,不是左值
            v3 = incr(v1+v2); //錯誤,加起來也不是左值
            int v4 = incr(v3); //正确,v3是int
         }
               
    應該将不需要修改的引用形參定義為const引用。普通的非const引用形參在使用時不太靈活,這樣的形參既不能用const對象初始化,也不能用字面值實參或者産生右值的表達式的實參初始化。
  • 傳遞指向指針的引用

    通過實作兩個指針的交換,實作交換兩個整數的函數

    void ptrswap(int *&v1, int *&v2)  
        {
          int *temp = v2;
          v2 = v1;
          v1 = temp;
        }
               
    int *&v1 從右至左了解,隻是傳進ptrwasp 函數的任一指針的别名
    int main()
           {
              int i = ;
              int j = ;
              int *pi = &i ;
              int *pj = &j ;
              cout<<"Before ptrswap():\t *pi:"<< *pi<<"\t *pj:"<< *pj<<endl;
              ptrswap(pi,pj);
              cout<<"After ptrswap():\t *pi:"<< *pi<<"\t *pj:"<< *pj<<endl;
              return ;
           }
               

    執行結果為:

    Before ptrswap(): *pi :10 *pj:20

    After ptrswap(): *pi :20 *pj:10

    即指針的值被調換了。之前pi指向i,pj指向j,現在pi指向j,pj指向i。

繼續閱讀