91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

引用的本質分析(四)

發布時間:2020-08-05 01:59:01 來源:網絡 閱讀:1186 作者:上帝之子521 欄目:編程語言

        我們上節講了 C++ 中的引用,那么我們就來看下引用的本質引用作為變量別名而存在,因此在一些場合可以代替指針。引用相對于指針來說具有更好的可讀性和實用性。注意:函數中的引用參數不需要進行初始化!

        下來我們來看看 swap 函數的實現對比,如下

void swap(int* a, int* b)    // 指針形式的
{
    int t = *a;
    *a = *b;
    *b = t;
}

void swap(int& a, int& b)    // 引用形式的
{
    int t = a;
    a = b;
    b = t;
}

        那么這塊就有個特殊的引用,便是 const 引用了。在 C++ 中可以聲明 const 引用,它的格式為 const Type& name = var;const 引用讓變量擁有只讀屬性。當使用常量對 const 引用進行初始化時,C++ 編譯器會為常量值分配空間并將引用作為這段空間的別名。使用常量對 const 引用初始化后將生成一個只讀變量!

        下來我們以代碼為例進行分析,看看引用的特殊意義,代碼如下

#include <stdio.h>

void Example()
{
    printf("Example:\n");
    
    int a = 3;
    const int& b = a;
    int* p = (int*)&b;
    
    // b = 5;
    
    *p = 5;
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);
}

void Demo()
{
    printf("Demo:\n");
    
    const int& c = 1;
    int* p = (int*)&c;
    
    // c = 5;
    
    *p = 5;
    
    printf("c = %d\n", c);
}

int main(int argc, char *argv[])
{
    Example();
    
    printf("\n");
    
    Demo();
    
    return 0;
}

        我們在 Example 函數中定義了變量 a,用 b const 引用 a,然后用指針 p 指向 b。然后通過指針 p 改變 b 的值,但是這塊 b 是 const 引用,所以不能直接改變 b。我們看看 a 和 b 會是多少。在 Demo 函數中,我們通過 const 引用 c 為 1,并且定義指針 p 指向它。同樣不能直接改變 c,但是可以通過指針 p 來改變它的值。我們先來看看通過指針 p 改變后的值是否為 5 呢?看看編譯結果

引用的本質分析(四)

        我們看到值已經都改變了,我們再來去掉第 11 和 26 行的注釋,看看直接改變 const  引用會怎樣?引用的本質分析(四)

        我們看到報的都是它們是只讀變量。那么我們思考下:引用有自己的存儲空間嗎?我們通過程序來看看

#include <stdio.h>

struct test
{
    char& c;
};

int main(int argc, char *argv[])
{
    char c = 'c';
    char& rc = c;
    test r = { c };
    
    printf("sizeof(char&) = %d\n", sizeof(char&));
    printf("sizeof(rc) = %d\n", sizeof(rc));
    
    printf("sizeof(test) = %d\n", sizeof(test));
    printf("sizeof(r.c) = %d\n", sizeof(r.c));
    
    return 0;
}

        我們在第 3 行定義了一個結構體變量 test,但它里面只有一個 char 類型的引用 c。我們來看看這個結構體占用內存嗎?編譯如下

引用的本質分析(四)

        我們看到引用本身只占用了一個字節,但是結構體 test 占用了 4 個字節的內存。我們猜想它是不是跟指針有某種聯系呢?其實引用在 C++ 中的內部實現是一個指針常量。關系如下

引用的本質分析(四)

        注意:a> C++ 編譯器在編譯過程中用 指針常量 作為引用的內部實現,因此引用所占的空間大小與指針相同;b> 從使用的角度,引用只是一個別名,C++ 為了實用性而隱藏了引用的存儲空間這一細節。下來我們通過一個示例代碼進行說明

#include <stdio.h>

struct TRef
{
    char* before;
    char& ref;
    char* after;
};

int main(int argc, char* argv[])
{
    char a = 'a';
    char& b = a;
    char c = 'c';

    TRef r = {&a, b, &c};

    printf("sizeof(r) = %d\n", sizeof(r));
    printf("sizeof(r.before) = %d\n", sizeof(r.before));
    printf("sizeof(r.after) = %d\n", sizeof(r.after));
    printf("&r.before = %p\n", &r.before);
    printf("&r.after = %p\n", &r.after);

    return 0;
}

        我們看到在結構體 TRef 內部只有 3 個成員,兩個指針,一個引用。我們通過打印結構體的大小和它的 before 指針和 after 指針的大小和地址來分別看看中間的引用究竟是什么

引用的本質分析(四)

        我們看到結構體總共占 12 個字節的內存,指針 before 和 after 各占 4 個字節,并且他們的地址相差 8,從而雙重說明了中間的引用占 4 個字節的內存空間,引用便是指向一個地址的。那么它的本質便是指針了。

        那么為什么還要弄個引用來代替指針呢?我們知道在 C 語言中,凡是涉及到指針的操作都是容易出 bug 的地方,因此 C++ 設計了引用來在大部分情況下代替指針。從功能性來說,可以滿足大多數的需要使用指針的場合;從安全性來說,可以避免由于操作指針不當而帶來的內存錯誤;從操作性來說,簡單易用,又不失功能強大。下面我們來看看函數返回引用的一個示例

#include <stdio.h>

int& demo()
{
    int d = 0;
    
    printf("demo: d = %d\n", d);
    
    return d;
}

int& func()
{
    static int s = 0;
    
    printf("func: s = %d\n", s);
    
    return s;
}

int main(int argc, char* argv[])
{
    int& rd = demo();
    int& rs = func();
    
    printf("\n");
    printf("main: rd = %d\n", rd);
    printf("main: rs = %d\n", rs);
    printf("\n");
    
    rd = 10;
    rs = 11;
    
    demo();
    func();
    
    printf("\n");
    printf("main: rd = %d\n", rd);
    printf("main: rs = %d\n", rs);
    printf("\n");

    return 0;
}

        我們在 demo 函數里返回了局部變量 d,因此這個肯定會出問題。在 func 函數里返回的加 static 修飾的變量,因此它是會放在全局數據區,不會出錯。我們在第 23 和 24 行用 demo 和 func 函數進行初始化,因此這會打印出 d = 0 和 s = 0;在第 27 和 28 行打印 rd 和 rs 的值,因為 demo 函數返回之后 d 會丟失,這時 rd 便是一個野指針了。所以 rd 指向的是一個隨機數,但是 rs 還是為 0;第 31 和 32 行分別對 rd 和 rs 進行重新賦值,再次調用 demo 和 func 函數時,d 還是為 0,s 就為 11 了;最后第 38 和 39 行會打印出 rd 為隨機數,rs 為 11。我們來看看編譯結果和我們分析的是否一致

引用的本質分析(四)

        我們看到它在編譯的時候都已經報警告了,打印的結果和我們所分析的是一致的。通過對引用本質的學習,總結如下:1、引用作為變量別名而存在旨在代替指針;2、const 引用可以使得變量具有只讀屬性;3、引用在編譯器內部使用指針常量實現,它的最終本質為指針;4、引用可以盡可能的避開內存錯誤


        歡迎大家一起來學習 C++ 語言,可以加我QQ:243343083

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新巴尔虎右旗| 连江县| 临颍县| 潼南县| 云林县| 麻阳| 曲水县| 奉节县| 高青县| 蚌埠市| 岫岩| 龙门县| 新巴尔虎右旗| 开远市| 通化市| 西和县| 宁海县| 化隆| 仙桃市| 彰化县| 和龙市| 尼勒克县| 铜鼓县| 大新县| 临沧市| 青龙| 剑川县| 保定市| 北安市| 尤溪县| 沛县| 灌云县| 吕梁市| 尖扎县| 西乡县| 双峰县| 商丘市| 方山县| 宾川县| 广饶县| 浪卡子县|