如何理解引用 1
在使用上,我們要把引用當成另一個對象的“別名”
即看到一個引用,我們可以直接把它腦補成原來的對象
這樣會衍生出引用的一系列特性(與指針相比):
- 引用被創建時必須被初始化,也叫“綁定”(指針則可以在任何時候被初始化)
- 不能有NULL 引用,引用必須與合法的存儲單元關聯(指針則可以是NULL)
- 引用初始化后不能改變引用的對象(指針則可以隨時改變所指的對象)
引用如何實現
實際上如果查看匯編代碼的話,引用是通過指針實現的
int a = 55;
int &b = a;
int * const c = &a;
這一段代碼會被編譯器翻譯為:
movl $55, -28(%rbp) // *(-28(%rbp)) =55; 即 int a = 55
leaq -28(%rbp), %rax
movq %rax, -16(%rbp) // -16(%rbp) = -28(%rbp); 即 int &b = a;
leaq -28(%rbp), %rax
movq %rax, -24(%rbp) // -24(%rbp) = -28(%rbp); 即 int * const c = &a;
可以看到雖然b是a的引用,但在實現上並不是簡單的替換,而是生成了b的空間存儲a的地址,和指針c的實現是相同的。即引用在實現上相當於是一個指針常量 。[指針常量與常量指針]
如何理解引用 2
我們可以看到,引用只是一種概念上的抽象,那在C++中為什么同時存在引用和指針呢?什么情況下使用引用呢?
結論1:C++的引用主要是為了支持運算符重載;指針的存在主要是為了兼容C語言。[為什么 C++ 有指針了還要引用?]
結論2:用戶自定義類型最好用引用傳參,這樣可以避免不必要的構造函數和析構函數調用;對於內置(C-like)類型,按值傳參會比按引用傳參更高效。[內置類型傳值效率高的原因]
引用的一些特性
有了這兩層對引用的理解,我們就可以解釋引用的下面這些特性了:
引用++
是原來的對象執行自增(引用是對象的別名)sizeof(引用)
的大小是被綁定的對象的大小(引用是對象的別名)- 一個類的成員變量帶引用,此引用 必須顯示在初始化列表初始化(引用在創建時必須初始化)
- 一個類的成員變量帶引用,此引用 給類的大小貢獻一個地址的長度(引用在實現上是指針)