程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 詳解C++引用——帶你走進引用的世界

詳解C++引用——帶你走進引用的世界

編輯:C++入門知識

原文鏈接:http://blog.csdn.net/u011421608/article/details/30750355

一、介紹引用

 

首先說引用是什麼,大家可以記住,引用就是一個別名,比如小王有個外號叫小狗,他的媽媽喊小狗回家吃飯,那就是在喊小王回家吃飯。

接下來我們用兩行代碼來聲明一個引用(就拿小王和小狗來說吧):

int xiaoW;

int &xiaoG=xiaoW;

上面就是一個引用,說明幾點要注意的地方:

1.&不是取地址符,而是引用運算符;

2.xiaoG是xiaoW的別名,所以這兩個變量的值和地址都是一樣的;

3.引用只能初始化,而不能先聲明再賦值,因為引用就相當於一個常量;

4.在聲明一個引用時必須同時對其進行初始化。

引用是非常忠心的,如果你定義了一個變量的別名,那麼這個別名永遠屬於這個變量,它的地址始終和變量的地址相同,當改變別名的值也會改變這個變量的值。

同樣,對對象的引用也與對變量的引用相同,但需要注意的是不能對類引用,因為類是一種類型,沒有內存地址。

關於引用的介紹就到這裡,下面我們來學習一下引用的使用。

 

二、三種傳參方式的比較

 

函數的傳參方式有三種:按值傳遞、按地址傳遞及按別名傳遞(按別名傳遞也是按地址傳遞的一種,這裡我為了方便講解把它單列出來)。接下來我們用三個程序來對三種方式作下比較,程序的功能是交換兩個變量的值。

 

1.按值傳遞。

#include

 

using namespace std;

 

void swap(int i,int j)

{

cout<<"交換前的i:"<

int temp;

temp=i;

i=j;

j=temp;

cout<<"交換後的i:"<

}

 

int main()

{

int a=1,b=2;

cout<<"交換前的a:"<

swap(a,b);

cout<<"交換後的a:"<

return 0;

}

程序的運行截圖如下:

 

\

從結果我們可以看出,變量a和b的值分別傳給i和j,函數內的i和j的值是交換了的,而a和b的值並未交換,這是怎麼回事呢。

這是因為,當把a和b的值傳遞到函數中時,這種傳遞方式就是按值傳遞,編譯器會自動在棧中創建a和b的副本,然後再將a和b的副本傳遞給函數,這樣在函數中交換的是a和b的副本,而不是a和b本身。解決這樣的問題就要引入指針了。

 

2.按地址傳遞。

#include

 

using namespace std;

 

void swap(int *i,int *j)

{

cout<<"交換前的i:"<<*i<<" "<<"j:"<<*j<

int temp;

temp=*i;

*i=*j;

*j=temp;

cout<<"交換後的i:"<<*i<<" "<<"j:"<<*j<

}

 

int main()

{

int a=1,b=2;

cout<<"交換前的a:"<

swap(&a,&b);

cout<<"交換後的a:"<

return 0;

}

程序的運行截圖如下:

 

\

可以看到,這樣就可以交換a和b的值了,因為程序傳遞的是a和b的地址,所以在函數中可以通過地址直接訪問a和b,交換它們的值。

指針雖然可以實現交換的功能,但是使用起來比較麻煩,又不易閱讀,使用引用看起來就會直觀得多。

 

3.按別名傳遞

#include

 

using namespace std;

 

void swap(int &i,int &j)

{

cout<<"交換前的i:"<

int temp;

temp=i;

i=j;

j=temp;

cout<<"交換後的i:"<

}

 

int main()

{

int a=1,b=2;

cout<<"交換前的a:"<

swap(a,b);

cout<<"交換後的a:"<

return 0;

}

程序的運行截圖如下:

 

\

結果也是成功交換,程序看起來易懂,而且操作也方便不少。

 

三、傳遞對象

 

對象和變量一樣可以作為參數傳遞,而不一樣的是,對象可能包含有大量的數據,那麼用上述的三種方式分別傳遞對象是什麼樣子呢。

 

1.按值傳遞對象

當按值傳遞的參數是一個對象時,編譯器同樣會建立一個對象的副本,函數中返回對象時,同樣會建立對象的副本,當該對象的數據很多時,那對內存的消耗就非常大了,我們先來看按值傳遞的程序。

#include

 

using namespace std;

 

class A

{

public:

A(){cout<<"構造函數被調用\n"<

A(A&a){cout<<"拷貝構造函數被調用\n"<

~A(){cout<<"析構函數被調用\n"<

private:

int x;

};

 

A func(A a)

{

return a;

}

 

int main()

{

A a;

func(a);

return 0;

}

程序運行結果截圖如下:

 

 

\

由程序運行結果可以看出,執行了一次構造函數,兩次復制構造函數,三次析構函數,接下來我們對照程序結果和代碼分析一下(此處知識對新手十分重要,大家務必牢記!),main函數中創建了一個對象a,所以調用了構造函數,再將a傳遞到func函數中,這時會自動調用復制構造函數來創建對象a的副本,也就是說傳進func函數的是a的副本而不是a本身,func函數的返回值是對象,返回的方式也是按值返回,此時又自動調用復制構造函數創建返回值的副本,所以我們看到調用一次構造函數和兩次復制構造函數,相應也會調用三次析構函數釋放內存。

 

2.按地址傳遞對象

從按值傳遞對象的程序結果可以看出,這種方式的系統開銷是非常大的,而按地址傳遞則解決了這一問題。

 

#include

 

using namespace std;

 

class A

{

public:

A(){cout<<"構造函數被調用\n"<

A(A&a){cout<<"拷貝構造函數被調用\n"<

~A(){cout<<"析構函數被調用\n"<

private:

int x;

};

 

A func(A *a)

{

return *a;

}

 

int main()

{

A a;

func(&a);

return 0;

}

程序運行結果截圖如下:

 

\

可以看出,上面的程序避免了兩次復制構造函數的調用,因為在將對象a傳遞給func函數時傳進的是地址,func函數返回的同樣也是個地址。

 

3.按別名傳遞對象

#include

 

using namespace std;

 

class A

{

public:

A(){cout<<"構造函數被調用\n"<

A(A&a){cout<<"拷貝構造函數被調用\n"<

~A(){cout<<"析構函數被調用\n"<

private:

int x;

};

 

A &func(A &a)

{

return a;

}

 

int main()

{

A a;

func(a);

return 0;

}

程序運行結果截圖如下:

 

\

可以看出,按別名傳遞對象與按指針傳遞有同樣的效果,而實現起來又簡單的多,這裡給新手朋友們做出個小提示,就是func函數返回的類型是別名,如果想在main函數中接收這個別名,同樣也要用引用類型的數據接收,比如A &aa=func(a),而不能用一個A類型的對象接收,這點大家要注意。

 

四、到底該用指針還是引用

 

既然引用可以實現指針的功能,又比指針使用方便,那是不是只用引用就可以了呢,答案是否定的,因為指針的某些功能引用是無法實現的,先說一下引用和指針的區別。

1.指針可以為空,而引用不能為空;

2.指針可以被賦值,而引用不可改變;

3.在堆中創建一塊內存區域時,必須使用指針來指向這塊區域,否則是無法訪問的,而不能用引用來指向

 

五、使用引用需謹慎

 

引用是不能為空的,否則是得不到正確的結果,我們通過下面的程序來感受一下。

#include

 

using namespace std;

 

class A

{

public:

A(int i){x=i;}

int get(){return j;}

private:

int j;

};

 

A &func()

{

A a(100);

return a;

}

 

int main()

{

A&aa=func();

cout<

return 0;

}

程序運行結果截圖如下:

 

\

從運行結果可以看出,我們並沒有得到正確的j值(100),這是為什麼呢,原因是,func函數中的a是一個局部對象,在func函數運行後,a就沒有了,所以func函數返回的是一個並不存在的對象的別名,因此無法正確得到j的值,解決這個問題很容易,只要將func函數的引用類型返回值改為A類型,就可以的到正確的結果,因為這樣會創建一個對象a的副本。

 

六、寄語

 

我剛開始學習C++時對引用就特別頭疼,但只要清晰的了解了它的工作方式,學習起來還是比較簡單的,所以我以我的親身體驗寫出這篇博文,以供初學者朋友參考。當然,引用的知識比較混亂而且極容易與指針混淆,需要在應用的過程中才能逐漸掌握,所以建議朋友們還是去多讀多寫代碼。祝朋友們都能學到足夠的知識,在實踐中進步,成為合格的互聯網人才。

由於我也是剛入門不久,所以纰漏之處在所難免,請各位多包涵,如果對本文有任何意見或建議,歡迎與我qq交流,謝謝!


yuan 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved