1、C++ Primer提到:引用並非對象,相反的,它只是爲一個已經存在的對象所起的另外一個名字。
引用的定義必須伴隨初始化,而且一旦定義了引用,就無法令其再綁定到另外的對象,之後每次使用這個引用都是訪問它最初綁定的那個對象。
2、何爲對象?
對於面向對象來說,對象就是類的實例,是抽象化的數據本身。
更廣義的來說,一個int型變量可以是對象,一個指針也可以是對象,但一個引用卻又不是對象。可以理解:在語言層面上,佔用內存的變量都可以稱之爲對象。
3、引用佔內存嗎?
在語言層面上:不佔內存!
不信看下面的簡單程序:
void function()
{
int x = 0;
int& r = x;
int* p1 = &x;
int* p2 = &r;
std::cout << p1 << std::endl;
std::cout << p1 << std::endl;
return 0;
}
輸出:
0x7ffcb64d705c
0x7ffcb64d705c
4、窺視底層呢?
再來看一段代碼:
int function() {
int x = 0;
int* ptr = &x;
int& r = x;
r = 1;
return r;
}
彙編代碼:
pushq %rbp
movq %rsp, %rbp //拷貝棧指針
movl $0, -20(%rbp) //int x = 0
leaq -20(%rbp), %rax
movq %rax, -8(%rbp) //int* ptr = &x
leaq -20(%rbp), %rax
movq %rax, -16(%rbp) //int& r = x
movq -16(%rbp), %rax
movl $1, (%rax) //r = 1
movq -16(%rbp), %rax
movl (%rax), %eax
popq %rbp
ret //return r
movl $0, -20(%rbp)
首先在棧的%rbp-20的地方分配了一個4字節的空間儲存變量x=0;
leaq -20(%rbp), %rax
movq %rax, -8(%rbp)
把x的地址保存到%rbp-8的棧空間處,int* ptr = &x;
leaq -20(%rbp), %rax
movq %rax, -16(%rbp)
把x的地址保存到%rbp-16的棧空間處, int& r = x;
movq -16(%rbp), %rax
movl $1, (%rax)
將%rbp-16棧空間處的值改寫成1, r = 1;
movq -16(%rbp), %rax
movl (%rax), %eax
popq %rbp
ret
將%rbp-16棧空間處的值返回, return r;
思路很清晰了。創建指針和創建引用的彙編代碼幾乎完全一樣,在棧上分配空間,保存變量x的地址,所有對引用變量r的操作實際都是通過這個地址在操作x。
和指針有區別嗎?沒有。
佔用內存嗎?從底層來看,確實佔用了內存。
5、小結
本質上,引用和指針沒有區別。只不過在語言層面上,C++設計者將通過指針來操作引用的實現細節隱藏了。不過,我們依然可以肯定:
(1)定義一個引用就是定義一個指針,這個指針保存引用對象的地址,且指針類型爲const,不可以再指向其他對象;
(2)每次對引用變量的使用,實際都伴隨着解引用,知識我們看不到符號*;