對於習慣使用
c進行開發的朋友們,在看到
c++**現的
&符號,可能會犯迷糊,因為在
c語言中這個符號表示了取位址符,但是在
c++中它卻有著不同的用途,掌握
c++的
&符號,是提高**執行效率和增強**質量的乙個很好的辦法。
引用是c++引入的新語言特性,是
c++常用的乙個重要內容之一,正確、靈活地使用引用,可以使程式簡潔、高效。我在工作中發現,許多人使用它僅僅是想當然,在某些微妙的場合,很容易出錯,究其原由,大多因為沒有搞清本源。故在本篇中我將對引用進行詳細討論,希望對大家更好地理解和使用引用起到拋磚引玉的作用。
一、引用簡介
引用就是某一變數(目標)的乙個別名,對引用的操作與對變數直接操作完全一樣。
引用的宣告方法:型別識別符號
&引用名
=目標變數名; 【例
1】:int a; int &ra=a; //
定義引用
ra,它是變數
a的引用,即別名
說明: (
1)&在此不是求位址運算,而是起標識作用。 (
2)型別識別符號是指目標變數的型別。 (
3)宣告引用時,必須同時對其進行初始化。 (
4)引用宣告完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,且不能再把該引用名作為其他變數名的別名。
ra=1;
等價於a=1; (
5)宣告乙個引用,不是新定義了乙個變數,它只表示該引用名是目標變數名的乙個別名,它本身不是一種資料型別,因此引用本身不佔儲存單元,系統也不給引用分配儲存單元。故:對引用求位址,就是對目標變數求位址。
&ra與
&a相等。 (
6)不能建立陣列的引用。因為陣列是乙個由若干個元素所組成的集合,所以無法建立乙個陣列的別名。
二、引用應用
1、引用作為引數
引用的乙個重要作用就是作為函式的引數。以前的
c語言中函式引數傳遞是值傳遞,如果有大塊資料作為引數傳遞的時候,採用的方案往往是指標,因為這樣可以避免將整塊資料全部壓棧,可以提高程式的效率。但是現在(
c++中)又增加了一種同樣有效率的選擇(在某些特殊情況下又是必須的選擇),就是引用。 【例
2】:void swap(int &p1, int &p2) //
此處函式的形參
p1, p2
都是引用
為在程式中呼叫該函式,則相應的主調函式的呼叫點處,直接以變數作為實參進行呼叫即可,而不需要實參變數有任何的特殊要求。如:對應上面定義的
swap
函式,相應的主調函式可寫為:
main( )
上述程式執行時,如果輸入資料
10 20
並回車後,則輸出結果為
20 10。
由【例2
】可看出: (
1)傳遞引用給函式與傳遞指標的效果是一樣的。這時,被調函式的形參就成為原來主調函式中的實參變數或物件的乙個別名來使用,所以在被調函式中對形參變數的操作就是對其相應的目標物件(在主調函式中)的操作。 (
2)使用引用傳遞函式的引數,在記憶體中並沒有產生實參的副本,它是直接對實參操作;而使用一般變數傳遞函式的引數,當發生函式呼叫時,需要給形參分配儲存單元,形參變數是實參變數的副本;如果傳遞的是物件,還將呼叫拷貝建構函式。因此,當引數傳遞的資料較大時,用引用比用一般變數傳遞引數的效率和所佔空間都好。 (
3)使用指標作為函式的引數雖然也能達到與使用引用的效果,但是,在被調函式中同樣要給形參分配儲存單元,且需要重複使用
"*指標變數名
"的形式進行運算,這很容易產生錯誤且程式的閱讀性較差;另一方面,在主調函式的呼叫點處,必須用變數的位址作為實參。而引用更容易使用,更清晰。
如果既要利用引用提高程式的效率,又要保護傳遞給函式的資料不在函式中被改變,就應使用常引用。 2
、常引用
常引用宣告方式:
const
型別識別符號
&引用名
=目標變數名;
用這種方式宣告的引用,不能通過引用對目標變數的值進行修改
,從而使引用的目標成為
const
,達到了引用的安全性。 【例
3】:int a ;
const int &ra=a;
ra=1; //
錯誤a=1; //正確
這不光是讓**更健壯,也有些其它方面的需要。 【例
4】:假設有如下函式宣告:
string foo( );
void bar(string & s);
那麼下面的表示式將是非法的:
bar(foo( ));
bar("hello world");
原因在於
foo( )
和"hello world"
串都會產生乙個臨時物件,而在
c++中,這些臨時物件都是
const
型別的。因此上面的表示式就是試圖將乙個
const
型別的物件轉換為非
const
型別,這是非法的。
引用型引數應該在能被定義為
const
的情況下,盡量定義為
const 。
3、引用作為返回值
要以引用返回函式值,則函式定義時要按以下格式:
型別識別符號
&函式名(形參列表及型別說明)
說明: (
1)以引用返回函式值,定義函式時需要在函式名前加&
(2)用引用返回乙個函式值的最大好處是,在記憶體中不產生被返回值的副本。 【例
5】以下程式中定義了乙個普通的函式
fn1(它用返回值的方法返回函式值),另外乙個函式
fn2,它以引用的方法返回函式值。
#include
float temp; //
定義全域性變數
temp
float fn1(float r); //
宣告函式
fn1float &fn2(float r); //
宣告函式
fn2float fn1(float r) //
定義函式
fn1,它以返回值的方法返回函式值
float &fn2(float r) //
定義函式
fn2,它以引用方式返回函式值
void main() //
主函式} (
5)在另外的一些操作符中,卻千萬不能返回引用:
+-*/
四則運算符。它們不能返回引用,
effective c++[1]
的item23
詳細的討論了這個問題。主要原因是這四個操作符沒有
side effect
,因此,它們必須構造乙個物件作為返回值,可選的方案包括:返回乙個物件、返回乙個區域性變數的引用,返回乙個
new分配的物件的引用、返回乙個靜態物件引用。根據前面提到的引用作為返回值的三個規則,第2、
3兩個方案都被否決了。靜態物件的引用又因為
((a+b) == (c+d))
會永遠為
true
而導致錯誤。所以可選的只剩下返回乙個物件了。 4
、引用和多型
引用是除指標外另乙個可以產生多型效果的手段。這意味著,乙個基類的引用可以指向它的派生類例項。 【例
7】:class
a;class b:
public a;
b b;
a &ref = b; //
用派生類物件初始化基類物件的引用
ref
只能用來訪問派生類物件中從基類繼承下來的成員,是基類引用指向派生類。如果
a類中定義有虛函式,並且在
b類中重寫了這個虛函式,就可以通過
ref產生多型效果。
三、引用總結(1
)在引用的使用中,單純給某個變數取個別名是毫無意義的,引用的目的主要用於在函式引數傳遞中,解決大塊資料或物件的傳遞效率和空間不如意的問題。 (
2)用引用傳遞函式的引數,能保證引數傳遞中不產生副本,提高傳遞的效率,且通過
const
的使用,保證了引用傳遞的安全性。 (
3)引用與指標的區別是,指標通過某個指標變數指向乙個物件後,對它所指向的變數間接操作。程式中使用指標,程式的可讀性差;而引用本身就是目標變數的別名,對引用的操作就是對目標變數的操作。 (
4)使用引用的時機。流操作符
<<
和》、賦值操作符
=的返回值、拷貝建構函式的引數、賦值操作符
=的引數、其它情況都推薦使用引用。
C 中的引用
最近重新看c 看到些以前沒注意的dd,溫故而知新,暫且記下。引用是能自動間接引用的一種指標,即不必使用間接引用運算子 就可以得到乙個引用值。引用可以為變數起別名,它主要用作函式引數以及函式的返回型別。1 引用的定義 如 int i int j i j是i的引用。1 定義引用時,必須立即對它進行初始化...
C 中的引用
例1 int a int ra a 定義引用ra,它是變數a的引用,即別名 說明 1 在此不是求位址運算,而是起標識作用。2 型別識別符號是指目標變數的型別。3 宣告引用時,必須同時對其進行初始化。4 引用宣告完畢後,相當於目標變數名有兩個名稱,即該目標原名稱和引用名,且不能再把該引用名作為其他變數...
C 中的引用
引用是c 引入的新語言特性,是c 常用的乙個重要內容之一,正確 靈活地使用引用,可以使程式簡潔 高效。我在工作中發現,許多人使用它僅僅是想當然,在某些微妙的場合,很容易出錯,究其原由,大多因為沒有搞清本源。故在本篇中我將對引用進行詳細討論,希望對大家更好地理解和使用引用起到拋磚引玉的作用。一 引用簡...