C++ 引用

引用: 就是某一變量(目標(biāo))的一個別名, 對引用的操作與對變量直接操作完全一樣. 并不會為引用在內(nèi)存中分配內(nèi)存. 引用的地址與變量的地址是一致的.

1. 引用的定義

  • 類型標(biāo)識符 &引用名=目標(biāo)變量名见咒;
int a = 10;
int &b = a;
  • &在此不是求地址運(yùn)算符旗芬,而是起標(biāo)識作用公壤。
  • 聲明引用時感混,必須同時對其進(jìn)行初始化
  • 類型標(biāo)識符是指目標(biāo)變量的類型.
  • 引用聲明完畢后,相當(dāng)于目標(biāo)變量有兩個名稱即該目標(biāo)原名稱和引用名脖镀,且不能再把該引用名作為其他變量名的別名.
  • 聲明一個引用公给,不是新定義了一個變量基协,它只表示該引用名是目標(biāo)變量名的一個別名嗅蔬,它本身不是一種數(shù)據(jù)類型剑按,因此引用本身不占存儲單元,系統(tǒng)也不給引用分配存儲單元购城。故:對引用求地址吕座,就是對目標(biāo)變量求地址虐译。&b與&a相等
  • 不能建立數(shù)組的引用瘪板。因?yàn)閿?shù)組是一個由若干個元素所組成的集合,所以無法建立一個數(shù)組的別名.

2. 引用的使用場景

引用的一個重要作用就是作為函數(shù)的參數(shù), 在C語言中, 函數(shù)參數(shù)的傳遞是值傳遞, 如果有大數(shù)據(jù)作為參數(shù)傳遞時, 采用的方案是指針, 這樣可以避免將整塊數(shù)據(jù)全部壓棧, 可以提高效率. 但是在C++中, 可以使用引用來達(dá)到相同的效率.

例: 在C中, 將兩個數(shù)進(jìn)行交換, 需要傳遞地址. 如下所示

//引用的用處1
//在傳統(tǒng)的交換值的過程中, 需要將地址傳遞到函數(shù)中例如.
void swap1(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main() {
    int a = 10;
    int b = 20;
    cout<<"a="<<a<<",b="<<b<<endl;
    swap1(&a, &b);
    cout<<"a="<<a<<",b="<<b<<endl;
    return 0;
}

輸出內(nèi)容

a=10,b=20
a=20,b=10

那么使用引用也能達(dá)到一樣的效果.代碼如下

void swap2(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}
int main() {
    int a = 10;
    int b = 20;
    cout<<"a="<<a<<",b="<<b<<endl;
    swap2(a, b);
    cout<<"a="<<a<<",b="<<b<<endl;
    return 0;
}

輸出結(jié)果與上面一致. 所以 傳遞引用給函數(shù)和傳遞指針給函數(shù)的效果是一樣的.
這時, 被調(diào)用函數(shù)的形參就成為原來主函數(shù)中實(shí)參變量或?qū)ο蟮囊粋€別名來使用. 所以在被調(diào)用函數(shù)中對形參變量的操作就是對其相應(yīng)的目標(biāo)對象操作.

使用引用傳遞函數(shù)的參數(shù), 在內(nèi)存中并沒有產(chǎn)生實(shí)參的副本, 它是直接對實(shí)參進(jìn)行操作. 而一般變量傳遞函數(shù)的參數(shù), 當(dāng)發(fā)生函數(shù)調(diào)用時, 需要給形參分配內(nèi)存空間. 如果傳遞的是對象, 還需要將調(diào)用拷貝構(gòu)造函數(shù). 因此,當(dāng)參數(shù)傳遞的數(shù)據(jù)較大時, 用引用比一般變量傳遞參數(shù)的效率和所占空間都較好.

使用指針作為函數(shù)的參數(shù), 雖然能達(dá)到同樣的效果, 但是在被調(diào)用函數(shù)中同樣要給形參分配內(nèi)存, 且需要重復(fù)使用 * 指針變量名的形式進(jìn)行運(yùn)算, 容易產(chǎn)生錯誤, 可讀性差. 引用就較為清晰.

3. 常引用

如果要利用引用提高程序的效率, 又要保護(hù)傳遞給函數(shù)的數(shù)據(jù)不再函數(shù)內(nèi)被改變, 那么就要使用到常引用了.
常引用的聲明方式為: const 類型標(biāo)識符 & 引用名 = 目標(biāo)變量名
用這種方式聲明的引用, 不能通過引用對目標(biāo)變量的值進(jìn)行修改, 從而使引用的目標(biāo)成為const, 達(dá)到了引用的安全性.
例1:

void main(){
   int a=1;
   int &b=a;
   b=2;
   cout<<"a="<<a<<endl;//2
   int c=1;
   const int &d=c;
   // d=2;//編譯錯誤 error C2166: l-value specifies const object
   c=2;//正確
11 }

例2:
有以下兩個函數(shù)聲明

string foo();
void bar(string &s);

那么下面的兩個表達(dá)式是錯誤的.

bar(fool());
bar("hello");

原因在于傳入的foo()hello 都會產(chǎn)生一個臨時對象, 而在C++中, 臨時對象都是 const 類型的. 因此上面的表達(dá)式就是試圖將一個 const類型的對象轉(zhuǎn)換為非 const類型.

注意: 引用型參數(shù)應(yīng)該在能被定義為 const 的情況下, 盡量定義為 const

4. 引用作為返回值.

要以引用返回函數(shù)值, 則函數(shù)定義時要按以下格式.
類型標(biāo)識符 &函數(shù)名(形參及類型說明) { 函數(shù)體 }

  • 以引用返回函數(shù)值, 定義函數(shù)時, 需要在函數(shù)名前面加 &
  • 用引用返回一個函數(shù)值的最大好處是, 在內(nèi)存中不會產(chǎn)生被返回值的副本.
    例:
#include <iostream>
using namespace std;
int func1(int a) {
    int temp = a * a * 10;
    return temp;
}

int temp;
int & func2(int a) {
    temp = a * a * 20;
    //直接返回temp, 等價(jià)與
    //int &b = temp;
    //return b;
    return temp;
}

int main() {
    //第一種情況, 系統(tǒng)會生成要返回值的副本,即臨時變量.
    int r1 = func1(2);
    cout << "r1=" << r1 << endl;
    //情況2, 系統(tǒng)不會產(chǎn)生返回值的副本
    int r2 = func2(5);
    cout << "r2=" << r2 << endl;
    return 0;
}

引用作為返回值, 必須遵守以下規(guī)則.

  1. 不能返回局部變量的引用. 主要原因是局部變量會在函數(shù)返回后小會, 因此, 被返回的引用就成為了 "無所指" 的引用. 程序會進(jìn)入未知狀態(tài).
  2. 不能返回函數(shù)內(nèi)部使用new分配的內(nèi)存的引用. 雖然不存在局部變量的被動銷毀問題, 可對于這種情況, 會面臨其他尷尬的局面. 例如被函數(shù)返回的引用只是作為一個臨時變量出現(xiàn), 而沒有被賦予一個實(shí)際的變量, 那么這個引用所指向的空間(由new分配)就無法釋放, 造成memory leak.
  3. 可以返回類成員的引用, 但最好是 const. 主要原因是當(dāng)對象的屬性是與某種業(yè)務(wù)規(guī)則相關(guān)聯(lián)的時候, 其賦值常常與某些其他屬性或者對象的狀態(tài)有關(guān), 因此有必要將賦值操作封裝在一個業(yè)務(wù)規(guī)則中. 如果其他對象可以獲得該屬性的非常量引用/或指針, 那么該屬性的單純賦值就會破壞業(yè)務(wù)規(guī)則的完整性.

總結(jié)

  • 在引用的使用中, 單純給某個變量取個別名是毫無意義的, 引用的目的主要用于函數(shù)參數(shù)傳遞中, 解決大塊數(shù)據(jù)或?qū)ο蟮膫鬟f效率和空間不如意的問題.
  • 用引用傳遞函數(shù)的參數(shù), 能保證參數(shù)傳遞中不產(chǎn)生副本, 提高傳遞的效率, 且通過 const 的使用, 保證了引用傳遞的安全性
  • 引用與指針的區(qū)別是,指針通過某個指針變量指向一個對象后, 對它所指向的變量間接操作, 程序中使用指針, 可讀性差. 而引用本身就是目標(biāo)變量的別名, 對引用的操作就是對目標(biāo)變量的操作.
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末漆诽,一起剝皮案震驚了整個濱河市侮攀,隨后出現(xiàn)的幾起案子锣枝,更是在濱河造成了極大的恐慌,老刑警劉巖兰英,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撇叁,死亡現(xiàn)場離奇詭異,居然都是意外死亡畦贸,警方通過查閱死者的電腦和手機(jī)陨闹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來薄坏,“玉大人趋厉,你說我怎么就攤上這事〗鹤梗” “怎么了君账?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沈善。 經(jīng)常有香客問我乡数,道長,這世上最難降的妖魔是什么闻牡? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任净赴,我火速辦了婚禮,結(jié)果婚禮上罩润,老公的妹妹穿的比我還像新娘劫侧。我一直安慰自己,他們只是感情好哨啃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布烧栋。 她就那樣靜靜地躺著,像睡著了一般拳球。 火紅的嫁衣襯著肌膚如雪审姓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天祝峻,我揣著相機(jī)與錄音魔吐,去河邊找鬼。 笑死莱找,一個胖子當(dāng)著我的面吹牛酬姆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奥溺,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辞色,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浮定?” 一聲冷哼從身側(cè)響起相满,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤层亿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后立美,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匿又,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年建蹄,在試婚紗的時候發(fā)現(xiàn)自己被綠了碌更。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡洞慎,死狀恐怖针贬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拢蛋,我是刑警寧澤桦他,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站谆棱,受9級特大地震影響快压,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垃瞧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一蔫劣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧个从,春花似錦脉幢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至奕污,卻和暖如春萎羔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碳默。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工贾陷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘱根。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓髓废,卻偏偏與公主長得像,于是被迫代替她去往敵國和親该抒。 傳聞我的和親對象是個殘疾皇子慌洪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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