1. 程式人生 > >[轉載]C++中引用傳遞與指標傳遞區別(進一步整理)

[轉載]C++中引用傳遞與指標傳遞區別(進一步整理)

這篇文章是在學習了編譯原理引數傳遞後對c++和Java按引用傳遞的不同表現產生疑問,在網上搜索找到的博文,這裡提出了按地址傳遞和按引用傳遞是不同的,按我的個人理解,Java的物件引數的傳遞,是按地址傳遞,而按地址傳遞,需要有一個傳遞到被呼叫函式的指向實際引數地址的指標,這個指標是指向一個實參地址的指標變數,從這裡說,按地址傳遞可以算為按值傳遞的特殊情況,這裡的值是比較特別的指標變數的值。

以下是正文部分:

從概念上講。指標從本質上講就是存放變數地址的一個變數,在邏輯上是獨立的,它可以被改變,包括其所指向的地址的改變和其指向的地址中所存放的資料的改變。

而引用是一個別名,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化,而且其引用的物件在其整個生命週期中是不能被改變的(自始至終只能依附於同一個變數)。

在C++中,指標和引用經常用於函式的引數傳遞,然而,指標傳遞引數和引用傳遞引數是有本質上的不同的:

指標傳遞引數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在棧中開闢了記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的一個副本。值傳遞的特點是被調函式對形式引數的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。(這裡是在說實參指標本身的地址值不會變)

而在引用傳遞過程中,被調函式的形式引數雖然也作為區域性變數在棧中開闢了記憶體空間,但是這時存放的是由主調函式放進來的實參變數的地址。被調函式對形參的任何操作都被處理成間接定址,即通過棧中存放的地址訪問主調函式中的實參變數。正因為如此,被調函式對形參做的任何操作都影響了主調函式中的實參變數。

引用傳遞和指標傳遞是不同的,雖然它們都是在被調函式棧空間上的一個區域性變數,但是任何對於引用引數的處理都會通過一個間接定址的方式操作到主調函式中的相關變數。而對於指標傳遞的引數,如果改變被調函式中的指標地址,它將影響不到主調函式的相關變數。如果想通過指標引數傳遞來改變主調函式中的相關變數,那就得使用指向指標的指標,或者指標引用。

為了進一步加深大家對指標和引用的區別,下面我從編譯的角度來闡述它們之間的區別:

程式在編譯時分別將指標和引用新增到符號表上,符號表上記錄的是變數名及變數所對應地址。指標變數在符號表上對應的地址值為指標變數的地址值,而引用在符號表上對應的地址值為引用物件的地址值。符號表生成後就不會再改,因此指標可以改變其指向的物件(指標變數中的值可以改),而引用物件則不能修改。

最後,總結一下指標和引用的相同點和不同點:

★相同點:

●都是地址的概念;

指標指向一塊記憶體,它的內容是所指記憶體的地址;而引用則是某塊記憶體的別名。

★不同點:

●指標是一個實體,而引用僅是個別名;

●引用只能在定義時被初始化一次,之後不可變;指標可變;引用“從一而終”,指標可以“見異思遷”;

●引用沒有const,指標有const,const的指標不可變;(具體指沒有int& const a這種形式,而const int& a是有 的, 前者指引用本身即別名不可以改變,這是當然的,所以不需要這種形式,後者指引用所指的值不可以改變)

●引用不能為空,指標可以為空;

●“sizeof 引用”得到的是所指向的變數(物件)的大小,而“sizeof 指標”得到的是指標本身的大小;

●指標和引用的自增(++)運算意義不一樣;

●引用是型別安全的,而指標不是 (引用比指標多了型別檢查

一、引用的概念

引用引入了物件的一個同義詞。定義引用的表示方法與定義指標相似,只是用&代替了*。
例如: Point pt1(10,10);
Point &pt2=pt1; 定義了pt2為pt1的引用。通過這樣的定義,pt1和pt2表示同一物件。
需要特別強調的是引用並不產生物件的副本,僅僅是物件的同義詞。因此,當下面的語句執行後:
pt1.offset(2,2);
pt1和pt2都具有(12,12)的值。
引用必須在定義時馬上被初始化,因為它必須是某個東西的同義詞。你不能先定義一個引用後才
初始化它。例如下面語句是非法的:
Point &pt3;
pt3=pt1;
那麼既然引用只是某個東西的同義詞,它有什麼用途呢?
下面討論引用的兩個主要用途:作為函式引數以及從函式中返回左值。

二、引用引數

1、傳遞可變引數
傳統的c中,函式在呼叫時引數是通過值來傳遞的,這就是說函式的引數不具備返回值的能力。
所以在傳統的c中,如果需要函式的引數具有返回值的能力,往往是通過指標來實現的。比如,實現
兩整數變數值交換的c程式如下:
void swapint(int *a,int *b)
{
int temp;
temp=*a;
a=*b;
*b=temp;
}

使用引用機制後,以上程式的c++版本為:
void swapint(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
呼叫該函式的c++方法為:swapint(x,y); c++自動把x,y的地址作為引數傳遞給swapint函式。

2、給函式傳遞大型物件
當大型物件被傳遞給函式時,使用引用引數可使引數傳遞效率得到提高,因為引用並不產生物件的
副本,也就是引數傳遞時,物件無須複製。下面的例子定義了一個有限整數集合的類:
const maxCard=100;
Class Set
{
int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素個數的最大值。
int card; // 集合中元素的個數。
public:
Set () {card=0;} //建構函式
friend Set operator * (Set ,Set ) ; //過載運算子號*,用於計算集合的交集 用物件作為傳值引數
// friend Set operator * (Set & ,Set & ) 過載運算子號*,用於計算集合的交集 用物件的引用作為傳值引數

}
先考慮集合交集的實現
Set operator *( Set Set1,Set Set2)
{
Set res;
for(int i=0;i