天天看點

[從C到C++] 1.6 C++引用(Reference)

[TOC]

引用(Reference)是C++語言相對于C語言的又一個擴充,類似于指針,隻是在聲明的時候用&取代了*。引用可以看做是被引用對象的一個别名,在聲明引用時,必須同時對其進行初始化。引用的聲明方法如下:

[例1]C++引用示例:

在本例中,變量b就是變量a的引用,程式運作結果如下:

從這段程式中我們可以看出變量a和變量b都是指向同一位址的,也即變量b是變量a的另一個名字,也可以了解為0018FDB4空間擁有兩個名字:a和b。由于引用和原始變量都是指向同一位址的,是以通過引用也可以修改原始變量中所存儲的變量值,如例2所示,最終程式運作結果是輸出兩個20,可見原始變量a的值已經被引用變量b修改。

[例2]通過引用修改原始變量中的值:

如果我們不希望通過引用來改變原始變量的值時,我們可以按照如下的方式聲明引用:

這種引用方式成為常引用。如例3所示,我們聲明b為a的常引用,之後嘗試通過b來修改a變量的值,結果編譯報錯。雖然常引用無法修改原始變量的值,但是我們仍然可以通過原始變量自身來修改原始變量的值,如例3中,我們用a=20;語句将a變量的值由10修改為20,這是沒有文法問題的。

[例3]不能通過常引用來修改原始值:

通過例2,我們可以知道通過引用我們可以修改原始變量的值,引用的這一特性使得它用于函數傳遞參數或函數傳回值時非常有用。

如果我們在聲明或定義函數的時候将函數的形參指定為引用,則在調用該函數時會将實參直接傳遞給形參,而不是将實參的拷貝傳遞給形參。如此一來,如果在函數體中修改了該參數,則實參的值也會被修改。這跟函數的普通傳值調用還是有差別的。

[例3]函數的引用傳值:

運作結果:

在本例中我們将swap函數的形參聲明為引用,在調用swap函數的時候程式是将變量num1和num2直接傳遞給形參的,其中a是num1的别名,b是num2的别名,在swap函數體中交換變量a和變量b的值,也就相當于直接交換變量num1和變量num2的值了,是以程式最後num1=20,num2=10。

在C++中非void型函數需要傳回一個傳回值,類似函數形參,我們同樣可以将函數的傳回值聲明為引用。普通的函數傳回值是通過傳值傳回,即将關鍵字return後面緊接的表達式運算結果或變量拷貝到一個臨時存儲空間中,然後函數調用者從臨時存儲空間中取到函數傳回值,如例4所示。

[例4]函數的普通傳回值:

在例4中,valplus函數采用的是普通的傳值傳回,也即将變量a的結果加上5之後,将結果拷貝到一個臨時存儲空間,然後再從臨時存儲空間拷貝給num2變量。 當我們将函數傳回值聲明為引用的形式時,如例5所示。雖然例5運作結果和例4是相同的,但例5中的valplus函數在将a變量加上5之後,其運算結果是直接拷貝給num2的,中間沒有經過拷貝給臨時空間,再從臨時存儲空間中拷貝出來的這麼一個過程。這就是普通的傳值傳回和引用傳回的差別。

[例5]函數的引用傳回值:

此外,我們還需要注意一個小問題。如果我們将例5中的valplus函數定義成例6中所示的形式,那麼這段程式就會産生一個問題,變量b的作用域僅在這個valplus函數體内部,當函數調用完成,b變量就會被銷毀。而此時我們若将b變量的值通過引用傳回拷貝給變量num2的時候,有可能會出現在拷貝之前b變量已經被銷毀,進而導緻num2變量擷取不到傳回值。雖然這種情況在一些編譯器中并沒有發生,但是我們在設計程式的時候也是應該盡量避免這一點的。

在例4和例5中,我們就是為了避免這一點才采用的引用傳遞參數。普通的傳值傳回則不存在這樣的問題,因為編譯器會将傳回值拷貝到臨時存儲空間後再去銷毀b變量的。

[例6]一個可能擷取不到傳回值的例子:

繼續閱讀