復合類型是指基於其他類型而定義的類型。 而這里介紹的是引用和指針。並且指針和引用都提供了對其他對象的間接訪問。
引用
引用還是很好理解的,就是為對象起了另外一個名字,引用類型引用另外一種類型。 通常將聲明符協程 &d 的形式來定義引用類型,其中d是聲明的變量名。
注意:引用不是對象。
一般,在初始化變量時,如int a = 3; int b = a; 這時,這里b的初始化就會將a的值拷貝到新建的對象中。即int b = 3這里新建了一個對象來存儲,對a和b的操作是獨立的。 而定義引用時,程序會把引用和他的初始值綁定在一起,而不是將初始值拷貝給引用。如下所示:
#include <iostream> using namespace std; int main() { cout << "beginning!" << endl; int a = 2; int &b = a; cout << "b的值為:" << b << endl; // 2 b = 5; cout << "a的值為:" << a << "\t b的值為:" << b << endl; // a 和 b都是5 return 0; }
如上,我們可以看到:b就是a的引用,這里b的值也是2,所以引用就是給a了一個別名b,並且並沒有給b一個新的對象,而是將b和a綁定在了一起,我們修改b的值,發現a和b的值同時修改成了5,這就是引用。
那么引用的目的是怎樣的呢? 一般來說,引用比指針更容易操作、也更不容易出錯。可以代替指針。
需要注意的:
- 引用必須賦初值。
- 引用和之前的類型要嚴格匹配。
- 如上的int &b 是指引用類型b是指向int類型的引用。
指針
指針是指向另外一種類型的復合類型。
指針如果要指向某個對象,是存放着某個對象的地址。 如下:
int a = 10; int *p = &a; cout << &a << endl;
其中&a就是獲取a的地址。 int *p是指p是一個指向int類型對象的指針。
以上,我們已經定義了指針,那么如何利用指針訪問它所指的對象呢? 使用 * 解引用符即可。
int a = 10; int *p = &a; cout << *p << endl; // 10
如上所示: 我們可以得到 *p 的值為10。
注意: 某些符號具有多重含義!這里講解 * 和 &。
int i = 42;
int &r = i; // &緊隨類型名出現,這里的&為引用。
int *p; // *緊隨類型名出現,這里的 * 為定義指針類型的p。
p = &i; // 這里的&出現在表達式中,是一個取地址符。
*p = i; // 這里的 * 出現在表達式中,是一個解引用符。
int &r2 = *p; // 這里的 * 出現在表達式中,是一個解引用符。
空指針
即Null pointer,它是不指向任何對象的,一般我們建議:初始化所有的指針,並且在可能的情況下,盡量等定義了對象之后在定義指向他的指針,如果不清楚它指向何處,就初始化為空指針。
定義空指針一般有三種方法,如下所示:
#include <iostream> #include <cstdlib> using namespace std; void IsNull(int *p); int main() { cout << "beginning!" << endl; int *p = 0; IsNull(p); int *p1 = nullptr; IsNull(p1); int *p2 = NULL; IsNull(p2); int a = 5, *p3 = &a; IsNull(p3); return 0; } void IsNull(int *p) { if (p == nullptr) { cout << "空指針" << endl; } else { cout << "非空指針" << endl; } }
三種方法為賦值為0、賦值為NULL、賦值為 nullptr,最后一種方法是c++11所新定義的,也是我們推薦的,在判斷一個指針是否為空指針時,我們只需要判斷其是否與nullptr相等即可。 注意:NULL的值就是0,是在 cstdlib 庫中定義的。
注意:如果指針沒有初始化為空指針或者指向明確的對象,那么很有可能會導致整個程序的崩潰,並且難以入手解決問題。
int i = 42; int *pi = 0; // 定義pi為空指針 int *pi2 = &i; // pi2指向i cout << *pi2 << endl; int *pi3; pi3 = pi2; // 注意:這里並不是Pi3指向pi2,而是pi3指向了和pi2相同的對象,即這時pi3同樣指向i。 pi2 = 0; cout << *pi3; // 42 cout << *pi2; // 報錯
另外,如果指針指向為空,則if判斷時的結果為false,且指針之間可以使用 == 來判斷是否相等,比如指向同一個對象、都為空等等。
注意: void*指針可以存放任何類型的對象,不受限制,但利用也比較有限。
總結
指針和引用都提供了訪問對象的其他方法,但為什么c++中同時有指針和引用呢? 如下:
可以看到,在第一個例子中,顯然使用引用更加舒服一些。 另外,我們怎么理解這種參數的使用方式呢,實際,f1要求的兩個指針,比如f1在調用時是f1(p1, p2),即const complex * x = p1。 因為p1是指針,可以直接賦值。
指向指針的指針
int i = 42; int *p1 = &i; int *p2 = nullptr; p2 = p1; cout << *p2; //42
如上所示,p2 = p1的意思是p2指針指向p1指針所指向的對象,而不是p2指向p1,那么如何定義p2指向p1,即指向指針的指針呢?
int i = 42; int *p1 = &i; int **p2 = &p1; cout << **p2; //42
如上所示: p2就是一個指向指針的指針。
指向指針的引用
指針是對象,所以可以有指向指針的引用,如下:
int i = 42; int *p1 = &i; int *&r = p1; // 這里的r就是指向指針的引用 *r = 365; cout << *r; //365
如上所示:p1是指向int型變量i的指針,而 r 是指向指針型變量的引用,即我們對r的操作就是對p1的操作,因此,我們可以得到最后的結果為365。
參考鏈接:http://www.stroustrup.com/bs_faq2.html#pointers-and-references