【C++】C++學(xué)習(xí)筆記之四:引用、參數(shù)傳遞和返回值

1. 引用

1.1 左值引用

我們通常提到的引用都是指“左值引用”, 其語(yǔ)法如下:
<類型名> & <變量名> = <變量名>;
左值引用就是alias,相當(dāng)于給對(duì)象起了個(gè)別名,當(dāng)定義引用時(shí),編譯器會(huì)把引用型變量與它的初始值(也是個(gè)變量名)綁定在一起,使用引用型變量跟使用其初始值變量等同,同時(shí)改變。
一旦完成綁定(初始化),引用型變量會(huì)和它的初始值一直綁定在一起,因此不能將引用再重新綁定到另一個(gè)變量身上
對(duì)于重新綁定的問(wèn)題,來(lái)做個(gè)小實(shí)驗(yàn):

int main(int argc, char** argv){
        int i = 10;
        int ii = 12;
        int &a = i;
        a = ii;
        cout << "a:" << a << endl
             << "i:" << i << endl
             << "ii:" << ii << endl;
        return 0;
}

編譯后運(yùn)行,得到如下結(jié)果:


Paste_Image.png

【結(jié)論】:

由以上實(shí)驗(yàn)結(jié)果可以看到,對(duì)于已經(jīng)綁定了i的引用型變量a,對(duì)其再賦值變量ii,并沒(méi)有報(bào)語(yǔ)法錯(cuò)誤。但是,其實(shí)際的操作結(jié)果,并不像我們的本來(lái)意圖(想讓a再與ii綁定在一起),而是對(duì)本來(lái)綁定在一起的a和i變量做了一次賦值,把ii的值傳遞給了a和i兩個(gè)變量。
因此,以后在代碼中使用引用型變量時(shí),切記,一旦綁定關(guān)系成立,不要試圖解除綁定關(guān)系。結(jié)果很可能會(huì)事與愿違。

1.2 右值引用(C++11)

我們通常所說(shuō)的引用都是“左值引用”。還有一種形式的引用叫做“右值引用”,是對(duì)數(shù)值的引用。其語(yǔ)法如下:
<類型名> && <變量名> = <右值>;
其特點(diǎn)是:只能綁定到一個(gè)將要銷毀的對(duì)象上,其作用就是把右值資源“移動(dòng)”到另一個(gè)對(duì)象中去。
這里暫不探討。

2. 參數(shù)傳遞

參數(shù)傳遞發(fā)生在函數(shù)調(diào)用階段,函數(shù)定義中參數(shù)列表里的參數(shù)叫做形式參數(shù),實(shí)際調(diào)用函數(shù)時(shí)傳入的參數(shù)叫做實(shí)際參數(shù)

1.1 值傳遞(pass by value)

一般在參數(shù)傳遞的過(guò)程中,沒(méi)有特別標(biāo)注(不實(shí)用指針和引用),都是值傳遞,即在函數(shù)中發(fā)生的參數(shù)值的改變都是作用于形式參數(shù),而對(duì)實(shí)際參數(shù)沒(méi)有影響。
下面寫段代碼來(lái)觀察下值傳遞:

class varTest{
public:
    static void increase(int var){ 
        var++;
        cout << "var:" << var << endl;
    }
};
int main(int argc, char** argv){
        int i = 10;
        varTest::increase(i);
        cout << "i:" << i << endl;
        return 0;
}

程序編譯后運(yùn)行,得到如下結(jié)果:

Paste_Image.png

1.2 引用傳遞(pass by reference)

有了上面"引用綁定"和"形參實(shí)參關(guān)系"分析的基礎(chǔ),那么,函數(shù)參數(shù)以引用方式傳遞就很好理解了,就是把形參和實(shí)參綁定在一起,如果在函數(shù)體里對(duì)實(shí)參有修改,修改會(huì)真的起作用。
還是一段代碼,驗(yàn)證下:

class varTest{
public:
    static void increase(int &var){ 
        var++;
        cout << "var:" << var << endl;
    }
};
int main(int argc, char** argv){
        int i = 10;
        varTest::increase(i);
        cout << "i:" << i << endl;
        return 0;
}

編譯運(yùn)行結(jié)果:


Paste_Image.png

可以看到形參var和實(shí)參i的值都改變了。

1.3 常量型引用傳遞(pass by reference to const)

引用在編譯器底層的實(shí)現(xiàn)本質(zhì)上就是一個(gè)指針,或者說(shuō)跟指針的原理相同,這使它既能提高傳遞效率,同時(shí)看起來(lái)又好像是一個(gè)對(duì)象,使用起來(lái)更方便直觀。
所以現(xiàn)在一般都會(huì)建議程序員,在使用函數(shù)參數(shù)傳遞時(shí),盡量使用引用的方式傳遞,其開(kāi)銷相當(dāng)于一個(gè)4byte的指針類型的參數(shù)傳遞的開(kāi)銷。可以緩解函數(shù)調(diào)用時(shí)壓棧帶來(lái)的負(fù)擔(dān)。
但有些情況下,雖然傳遞引用型參數(shù)調(diào)用函數(shù)的效率會(huì)比較高,可是調(diào)用者也許并不希望函數(shù)內(nèi)部改變引用參數(shù)的數(shù)值,這就用到了傳遞常量型引用參數(shù)。

3.返回值

2.1 臨時(shí)變量與值傳遞返回值(return by value)

臨時(shí)變量通常指在一定生存周期(scope)范圍內(nèi)的變量,其在此范圍內(nèi)分配內(nèi)存(通常是棧上的內(nèi)存),跨出生命周期,變量的內(nèi)存將被釋放,變量消失。
前面說(shuō),盡量使用引用的方式傳遞參數(shù),同樣的道理也適用函數(shù)返回值的傳遞。但并不是所有情況下都可以用引用的方式返回值。當(dāng)返回值涉及到傳遞臨時(shí)變量就必須使用值傳遞的方式。
看代碼:

inline complex operator+(const complex& c1, const complex& c2){
     return complex(c1.re+c2.re, c1.im+c2.im);
}

2.2 引用傳遞返回值(return by reference)

直接看代碼:

inline complex operator+=(complex *ths, const complex & c){
    ths->re += c.re;
    ths->im += c.im;
    return *ths;
}

2.3 返回值傳遞到常量引用(return by reference to const)

返回值傳遞到常量引用跟返回值以引用方式傳遞一樣,其實(shí),函數(shù)開(kāi)發(fā)者,不需要關(guān)注引用型返回值是不是傳遞給了常量,傳遞給常量引用是使用者的考量。其編碼方式與上面的引用傳遞返回值是一樣的。
只不過(guò)要考率的地方是在調(diào)用時(shí),是否要使用常量引用型變量對(duì)返回值綁定的決策上。

【技巧】:參數(shù)和返回值傳遞的過(guò)程中,如果可以盡量使用引用的方式傳遞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,536評(píng)論 1 51
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,880評(píng)論 1 10
  • 常量與變量使用let來(lái)聲明常量,使用var來(lái)聲明變量。聲明的同時(shí)賦值的話,編譯器會(huì)自動(dòng)推斷類型。值永遠(yuǎn)不會(huì)被隱式轉(zhuǎn)...
    莫_名閱讀 462評(píng)論 0 1
  • 感賞女兒今天中午還在學(xué)校吃飯,我又可以放假啦!做完家務(wù)去媽媽家,好久沒(méi)有去了。我想幫媽媽做點(diǎn)家務(wù),媽媽說(shuō):不用不用...
    勿忘我瑤閱讀 98評(píng)論 5 3
  • 設(shè)置公私鑰 因?yàn)槲乙呀?jīng)有了一套GitHub的公密鑰,為默認(rèn)的id_rsa,所以還需要生成GitCafe的公密鑰,為...
    漫談理想李叔叔閱讀 391評(píng)論 0 1