想必你們對C++中的指針都有所瞭解,可是什麼是引用呢?C++11標準引入了「引用」的新功能。ios
引用(reference):給對象起了另一個名字,引用類型引用(refers to)另一種類型,經過將聲明符寫成&d的形式來定義引用類型,其中d是聲明的變量名:c++
int val = 1024; int &d = val;
能夠認爲變量名就是一個能夠操控內存的標籤,那麼引用就能夠理解爲另外一個標籤。新定義的標籤和原來的標籤均可以訪問存放在內存中的數據。
例如:安全
#include <iostream> #include <cmath> using namespace std; //聲明 void add(int &a,int b); bool& isZero(float f); int main(){ double dval = 0.1; double &d = dval; d+=0.1; cout << "d is " << d << endl; //使用引用做爲函數參數 int val = 20; add(val,5); cout << "val is " << val << endl; //使用引用做爲函數返回值 float fv = 0.000000004f; bool &v = isZero(fv); if(v) cout << "float 0.000000004 is zero" << endl; else cout << "float 0.000000004 is not zero" << endl; return 0; } //定義 void add(int &a,int b){ a+=b; } bool& isZero(float f){ bool b = false; if(abs(f) < 0.0000001) b = true; bool &rb = b;//不推薦返回局部變量的引用,由於當isZero函數執行完後,b變量的內存頗有可能會被回收 return rb; }
輸出結果爲:函數
d is 0.2
val is 25
float 0.000000004 is zero
C++官方推薦使用引用以一種更安全的方式向函數傳遞數據和獲取返回值。
可使用常量引用引用一個常量,
好比:spa
const int &i = 10;
指針(pointer):是能夠指向(point to)另一種數據類型的數據類型,經過將聲明符寫成*d的形式定義指針,其中d是變量名。
取地址符(&):獲取對象的地址。
解引用符(*):獲取指針所指向的對象。指針
int v = 10; int *p = &v; int **m = &p;
p是一個int類型的指針,指向一個int類型,上面的例子中指向了變量v。
m是一個int*類型的指針,指向一個int*類型,上面的例子中指向了變量p。
這裏說指向某個對象就是指存放某個對象的地址。指針就是指地址,地址就是指針。指針變量就是存放內存單元編號的變量,或者說指針變量就是存放內存地址的變量。
這張圖片解釋了上面這段代碼的地址指向問題,變量p存放了變量v的內存地址,變量m存放了變量p的內存地址。
在判斷某個對象的類型的時候,應該從右向左閱讀(離變量名最近的符號對變量類型有最直接的影響),好比c++11
int ****p; int ****&r = p;
上面的int ****p;離p最近的是第四個*,因此p是一個指針,剩餘的部分肯定該指針指向的類型,第四個*號左邊是int ***,因此指針p指向一個int ***類型。再看變量r,離r最近的是&,因此r是引用,剩餘的部分肯定該引用引用的類型,剩餘的是int ****,因此r引用了一個int ****類型的變量。
空指針不指向任何對象,使用字面值NULL表示,c++11標準還提供了字面值nullptr也能夠得到空指針。
void*是一種特殊的指針類型,可用於存聽任意對象的地址。一個void*指針存放着一個地址,這一點和其餘指針相似。可是不能直接操做void *指針所指的對象,由於並不知道對象究竟是什麼類型。若是要使用void *所指的對象,應該使用強制類型轉化。code
引用和指針的比較:
1.引用不能引用NULL。
2.一旦引用被初始化引向某一個對象後,它就不能再引向另外一個對象。指針能夠屢次改變指向的對象。
3.引用在建立的時候,必須初始化。指針能夠在被建立時不被初始化,能夠等須要的時才初始化。
4.引用不是對象,沒有實際的地址。指針是一個對象,有實際的地址。指針不能指向引用(由於引用不是對象)。對象