C++引用專題

  1. 引用鋪墊:變量名

變量名實(shí)質(zhì)上是一段連續(xù)存儲空間的別名疼鸟,是一個(gè)標(biāo)號(門牌號)翩腐,在程序中是通過變量來申請并命名內(nèi)存空間的窃肠,通過變量的名字可以直接使用對應(yīng)的內(nèi)存空間。

對一段內(nèi)存空間可以起除了變量名之外的其他別名垛玻,如果我們以“先入為主”的想法看待變量名和它對應(yīng)的內(nèi)存空間,那就是說:暫時(shí)地奶躯,這個(gè)變量名就是這段內(nèi)存空間帚桩。
那么引用(對這段內(nèi)存空間起了另外一個(gè)名字)的本質(zhì)就是變量的別名。

  1. 在C++中增加了引用的概念:引用可以看做一個(gè)已定義變量的別名嘹黔;
  • 引用的語法: <類型名>& <別名> = <原變量名>账嚎;
  1. 引用做函數(shù)參數(shù)
  • 普通的引用在聲明時(shí)必須使用其他的變量進(jìn)行初始化;

    引用作為函數(shù)參數(shù)聲明時(shí)不用進(jìn)行初始化儡蔓。
#include <iostream>

using namespace std;

void myswap(int &a, int &b) 
{
    int c = 0;

    c = a;
    a = b;
    b = c;
}

int main()
{

    int a = 10, b = 20;
    cout << "a: " << a << "\tb: " << b << endl;
    myswap(a, b);
    cout << "a: " << a << "\tb: " << b << endl;
    
    cout << "hello world.." << endl;
    return 0;
}
  1. 復(fù)雜數(shù)據(jù)類型的引用
#include <iostream>

using namespace std;

struct Teacher
{
    char name[64];
    int  age;
};

void printfT(Teacher *pT)
{
    cout << pT->age<<endl;
}

void printT2(Teacher &pT)
{
    cout << pT.age <<endl;  //  因?yàn)槭亲兞縿e名郭蕉,就把引用看做一個(gè)變量
}

int main()
{
    Teacher t1;
    t1.age = 35;
    printfT(&t1);
    printT2(t1);    // 引用做函數(shù)參數(shù)不用初始化,直接傳過去

    cout << "hello world ..." << endl;
    return 0;
}

  1. 引用的意義
  • 引用作為其他變量的別名存在喂江,在一些場合可以直接代替指針使用召锈;
  • 引用相對于指針來說,對程序員具有更好的可讀性(省去了輸入星號*還有括號)和實(shí)用性开呐;
  1. 引用的本質(zhì)
  • 5.1 引用在C++內(nèi)部就是一個(gè)常指針——指向一個(gè)固定的內(nèi)存空間
    variableType &name <==> variableType * const name;
  • 5.2 C++編譯器在編譯過程中使用常指針作用引用的內(nèi)部實(shí)現(xiàn)烟勋,因此引用占用的空間大小和一個(gè)指針變量相同,通過代碼的例子2有明確的演示
#include <iostream>

using namespace std;

struct Teacher
{
    /***************例子2******************/
    char name[64];  // 64byte
    int  age;       // 4byte
    double salary;   //12byte
    // 上面一共占80byte
    int  &a = age;  // 8byte
    // 再次測量共占空間88byte
};

int main()
{
    int a = 10;
    int &b =a;

    printf("sizeof (Teache)i: %d\n", sizeof(Teacher));

    /********例子1*****************************************/
    printf("&a: %d\n", (int *)&a);              /*********/
    printf("&b: %d\n", (int *)&b);              /*********/

    /***************顯示效果**********************************/
    /***********&a: 1670882700
    ***********&b: 1670882700
    *****************************************************/
    /************a和b就是統(tǒng)一段內(nèi)存空間的門牌號***********/
    /*****************************************************/

    cout << "hello world ..."  << endl;

    return 0;
}

  • 5.3 從實(shí)用的角度筐付,引用會讓讓人誤會其只是一個(gè)別名卵惦,沒有自己的內(nèi)存空間,但其實(shí)這是C++為了實(shí)用性而做出的細(xì)節(jié)隱藏瓦戚。
    程序員只需要給出實(shí)參變量沮尿,編譯器代替我們把定義指針和建立關(guān)聯(lián)一起做掉了。
void func(int &a)  |    void func(int *const a)
{                  |    { 
    a = 5;         |        *a = 5;
}                  |    }   

  1. 使用引用
    6.1 引用作為函數(shù)的返回值
    結(jié)論:若函數(shù)內(nèi)部的一個(gè)臨時(shí)變量要作為引用返回,則這段代碼是有風(fēng)險(xiǎn)的畜疾,盡量不要這么做赴邻。
    還是到代碼里面說問題。
#include <iostream>

using namespace std;

int& getAA2()
{
    int a;

    a = 10;
    return a;   //函數(shù)在這里試圖返回一個(gè)棧上的變量啡捶,而且返回類型是引用
} 

int main()
{
    int a2 = 0;
    a2 = getAA2();
    
    int &a3 = getAA2();    
    printf("a2: %d\n", a2);
    printf("a3: %d\n", a3);

    cout << "Hello world..." << endl;
    return 0;
}

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

  • windows:
    a2: 10
    a3: 20655117
    Hellod world...
    請按任意鍵繼續(xù)...
  • Ububtu:
    Command terminated

Press ENTER or type command to continue
發(fā)現(xiàn)在g++編譯器下代碼無法通過編譯姥敛,但是在VisualStudio 2015的編譯器雖然通過,但是a3的值是一堆亂碼瞎暑。
首先說明彤敛,g++編譯器在引用的上的檢查比VS2015嚴(yán)格一些, 而且編譯器提示:warning: reference to local variable ‘a(chǎn)’ returned 。
那么了赌,VS2015中的亂碼怎么出現(xiàn)墨榄?這需要繞一下來講。

我們已經(jīng)知道勿她,引用的實(shí)質(zhì)就是“常指針袄秩。”

  • 在a2 = getAA2();這一次調(diào)用中逢并,函數(shù)運(yùn)行到return a;

  • a是一個(gè)int類型變量之剧;

  • 返回值類型為int&引用,則返回機(jī)制創(chuàng)建的副本變量為:int& tempVariable = a;(我們借助這個(gè)tempVariable可以獲得較為直觀的理解)

  • 回到main函數(shù)初始的位置筒狠,a2 = getAA2(); 則即a2 = tempVarible; tempVariable是一個(gè)引用猪狈,本質(zhì)是常指針,指向了存儲函數(shù)的返回值的內(nèi)存地址(這個(gè)地址是什么暫時(shí)不清楚辩恼,應(yīng)該也不重要)雇庙。

  • 在int& a3 = getAA2();這一次調(diào)用中,函數(shù)運(yùn)行到return a;

  • a是一個(gè)int類型變量灶伊;

  • 返回值類型為int&引用疆前,則返回機(jī)制創(chuàng)建的副本變量為:int& tempVariable = a;(我們借助這個(gè)tempVariable可以獲得較為直觀的理解)

  • 回到main函數(shù)初始的位置,int& a3 = getAA2(); 則a3中保存的實(shí)際是一個(gè)常指針聘萨,它指向局部變量a的地址竹椒,但是a現(xiàn)在已經(jīng)被釋放,原來地址中是一個(gè)隨機(jī)的數(shù)值;

  • 而在后面的打印指令中米辐,編譯器檢測到要打印引用a3的值胸完,那么自動轉(zhuǎn)換為*(常指針),于是就取到了原來地址里面的隨機(jī)數(shù)翘贮。

至于g++編譯器赊窥,在檢測到引用作為了右值之后,代碼只要一執(zhí)行函數(shù)對用的語句狸页,就自動down掉了锨能。

所以說一條保守的結(jié)論就是:不要使用引用對變量賦初始值。
當(dāng)函數(shù)返回值為引用時(shí):
若返回棧變量,1)不能作為其他引用的初始值址遇;2)不能作為左值使用熄阻;
若返回靜態(tài)變量或全局變量,既可作為右值使用倔约,也可作為左值使用秃殉。

  1. 指針的引用
    在這部分使用代碼比較就可以看到使用指針引用的作用,它和C語言中的函數(shù)通過二級指針修改實(shí)參的內(nèi)容做的是一樣的事情跺株。
struct Teacher
{
    char name[64];
    int age;
};

// 在被調(diào)用函數(shù)中獲取資源
int getTeacher(Teacher **p)
{
    int nRet = 0;
    if (p == NULL) {
        nRet = -1;
        printf("func getTeacher():: detect that (p == NULL), error code: %d\n", nRet);
        return nRet;
    }

    Teacher *tmp = NULL;

    tmp = (Teacher *)malloc(sizeof(Teacher));
    if (tmp == NULL) {
        nRet = -2;
        printf("func getTeacher():: detect that (tmp == NULL), error code: %d\n", nRet);
        return nRet;
    }    
    tmp->age = 33;
    // *p是實(shí)參的地址 *實(shí)參的地址區(qū)間接地修改實(shí)參的值
    *p = tmp;
    
    return nRet;
}

int getTeacher2(Teacher * &myp)
{
    // c++中指針引用作為函數(shù)的參數(shù)就是這種形式:類型 + &引用名
    // Teacher *的意思就是說這是個(gè)Teacher類型的指針
    int nRet = 0;
    // 此處myp是實(shí)參的引用复濒,給myp賦值就是給main函數(shù)中的pT1賦值
    // 這里就是通過<指針的引用>達(dá)到了<二級指針>的效果
    myp = (Teacher *)malloc(sizeof(Teacher));
    if (myp == NULL) {
        nRet = -1;
        printf("func getTeacher2():: detects that (myp == NULL), error code: %d\n", nRet);
        return nRet;
    }

    myp->age = 36;  

    return nRet;
}

可以看到,這兩段函數(shù)實(shí)現(xiàn)的功能是一樣的乒省,但是代碼量相比后者要比前者少一些。因此C++中的引用幫助程序員節(jié)省了一些時(shí)間和操作畦木。

  1. 常引用
    引用分為常引用和普通引用袖扛。

其中,普通引用的形式如下

int a = 10;
int &b = a;

常引用的形式則是

int x = 10;
const int &y = x;

常引用的作用是讓變量擁有“只讀”屬性,不能用過引用去修改原來的變量的值十籍。

常引用的初始化蛆封,有兩種情況
1). 用變量初始化常引用

{
    // 用變量去初始化常引用
    int x1 = 30;
    const int &y = x1;
}

2). 用常量去初始化常引用

{
    const int a = r410;   // c++編譯器把a(bǔ)放在符號表中
    int &m = 41;        // 這個(gè)普通引用,引用的是一個(gè)字面量
    // 這時(shí)勾栗,字面量只是一個(gè)值惨篱,它是沒有內(nèi)存空間的
    // 但是引用的本質(zhì)就是給內(nèi)存起一個(gè)別名
    // 所以上面的這行代碼編譯器不會編譯通過,那么改怎么辦围俘?
    // 答案:加一個(gè)const砸讳!
    
    const int &m = 43;
    // c++編譯器是怎么工作的:
    // 編譯器會多分配一個(gè)內(nèi)存空間,賦值43.再把這個(gè)內(nèi)存空間起別名為:m



    const int &m = 42;
}

---END

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末界牡,一起剝皮案震驚了整個(gè)濱河市簿寂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宿亡,老刑警劉巖常遂,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挽荠,居然都是意外死亡克胳,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門圈匆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來漠另,“玉大人,你說我怎么就攤上這事臭脓⌒锍” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砚作。 經(jīng)常有香客問我窘奏,道長,這世上最難降的妖魔是什么葫录? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任着裹,我火速辦了婚禮,結(jié)果婚禮上米同,老公的妹妹穿的比我還像新娘骇扇。我一直安慰自己,他們只是感情好面粮,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布少孝。 她就那樣靜靜地躺著,像睡著了一般熬苍。 火紅的嫁衣襯著肌膚如雪稍走。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天柴底,我揣著相機(jī)與錄音婿脸,去河邊找鬼。 笑死柄驻,一個(gè)胖子當(dāng)著我的面吹牛狐树,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸿脓,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼抑钟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了答憔?” 一聲冷哼從身側(cè)響起味赃,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎虐拓,沒想到半個(gè)月后心俗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蓉驹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年城榛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片态兴。...
    茶點(diǎn)故事閱讀 40,561評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狠持,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞻润,到底是詐尸還是另有隱情喘垂,我是刑警寧澤甜刻,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站正勒,受9級特大地震影響得院,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜章贞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一祥绞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鸭限,春花似錦蜕径、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赡麦,卻和暖如春虹统,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背隧甚。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渡冻,地道東北人戚扳。 一個(gè)月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像族吻,于是被迫代替她去往敵國和親帽借。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評論 2 359

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