C++ 引用參數 深入分析

來源:互聯網
上載者:User

把參數聲明成引用,實際上改變了預設的按值傳遞參數的傳遞機制,在按值傳遞時,函數操縱的是實參的本地拷貝。
             

一、引用參數的三種常見用法:

1.需要改變實參的值,比如swap()。參數是引用時,函數接收的是實參的左值而不是值的拷貝。這意味著函數知道實參在記憶體中的位置,因而能夠改變它的值或取它的地址。
2.向主調函數返回額外的結果。如下例:

/********************************************************** Description:  測試引用傳遞的第二種使用方式* Author:charley* DateTime:2010-12-13 23:00* Compile Environment:win7 32 位 +vs2008***********************************************************/#include <iostream>#include <vector> using namespace std;// 引用參數 'occurs' 可以含有第二個傳回值 vector<int>::const_iterator look_up( const vector<int> &vec,  int value, // 值在 vector 中嗎?  int &occurs ) // 多少次? {  // res_iter 被初始化為最後一個元素的下一位置  vector<int>::const_iterator res_iter = vec.end(); occurs = 0; for ( vector<int>::const_iterator iter = vec.begin(); iter != vec.end(); ++iter ) {//判斷是否存在valueif ( *iter == value ) { //只有第一次找到value時,該項才成立;//找到第二個value時res_iter已經被下一步賦值了,該項不成立//達到在多次出現value的情況下,指向第一次出現的iterator 被返回if ( res_iter == vec.end() ) res_iter = iter; ++occurs; } }//如果找不到該value值,返問一個指向vector 最後一個元素下一位置的iteratorreturn res_iter; } /*** 調用look_up方法*/int main_test6(){vector<int> vInts;int iVal;cout<<"請輸入數字,按Ctrl+Z結束:"<<endl;while(cin>>iVal)vInts.push_back(iVal);if(vInts.size()==0){cout<<"沒有元素。"<<endl;return -1;}cout<<"您輸入的結果如下:"<<endl;for(vector<int>::const_iterator iter = vInts.begin();iter!=vInts.end();iter++)cout<<*iter<<"\t";cout<<endl;int occurs = 0;//尋找該容器中是否含有值2。vector<int>::const_iterator resIter = look_up(vInts,2,occurs);if(!occurs){cout<<"容器中不含2。"<<endl;}else{cout<<"容器中2出現了:"<<occurs<<"次,*iterator為:"<<*resIter<<endl;}return 0;}

3.向函數傳遞大型的類對象。例如:

class Huge { public: double stuff[1000]; };
extern int calc( const Huge & );
int main() {
Huge table[ 1000 ];
 
// ... 初始化 table
int sum = 0;
for ( int ix=0; ix < 1000; ++ix )
  // 函數 calc() 將指向 Huge 類型的數組元素指定為實參
  sum += calc( table[ix] );
 
// ...
}

二、如果引用參數不希望在被調用的函數內部被修改,那麼把參數聲明為 const 型的引用是個不錯的辦法。

如下例:

class X;
extern int foo_bar( X& );
 
int foo( const X& xx ) {
// 錯誤: const 傳遞給非 const
return foo_bar( xx );
}
為使該程式通過編譯 我們改變 foo_bar()的參數的類型 以下兩種聲明都是可以接受的 
extern int foo_bar( const X& );
extern int foo_bar( X ); // 按值傳遞

 

或者可以傳遞一個 xx 的拷貝做實參 允許 foo_bar()改變它 
int foo( const X &xx ) {
// ...
X x2 = xx; // 拷貝值
 
// 當 foo_bar() 改變它的引用參數時, x2 被改變, xx 保持不變
return foo_bar( x2 ); // ok
}

三、 我們可以聲明任意內建資料類型的引用參數

例如,如果程式員想修改指標本身,而不是指標引用的對象,那麼他可以聲明一個參數,該參數是一個指標的引用,例如:下面是交 換兩個指標的函數 

void ptrswap( int *&v1, int *&v2 ) {  int *tmp = v2;  v2 = v1;  v1 = tmp; } 

如下聲明 
int *&v1;   //實際是為指標取了一個別名,這樣就可以通過別名改變指標本身
應該從右向左讀,v1 是一個引用,它引用一個指標,指標指向 int 型的對象。

用函數 main() 操縱函數 rswap() 我們可以如下修改代碼以便交換兩個指標值:

#include <iostream>  void ptrswap( int *&v1, int *&v2 ); int main() {  int i = 10;  int j = 20;   int *pi = &i;  int *pj = &j;   cout << "Before ptrswap():\tpi: "   << *pi << "\tpj: " << *pj << endl; //參數為指標的別名(即指標的引用,那麼傳遞的實參就是指標本身,道理和傳遞普通變數一樣的) ptrswap( pi, pj );   cout << "After ptrswap():\tpi: "   << *pi << "\tpj: " << *pj << endl;  return 0; } 

編譯並運行程式 產生下列輸出 
Before ptrswap(): pi: 10 pj: 20
After ptrswap(): pi: 20 pj: 10

四、引用參數還是指標參數

這2種參數都能夠改變實參的值,也可以有效傳遞大型類對象,怎麼樣決定參數該聲明成哪種呢?

根本區別是:引用必須被初始化為指向一個對象,一旦初始化了,它就不能再指向其他對象;指標可以指向一系列不同的對象也可以什麼都不指向 。

因為指標可能指向一個對象或沒有任何對象,所以函數在確定指標實際指向一個有效對象之前不能安全地解引用(dereference) 一個指標,例如: 
class X;
void manip( X *px )
{
// 在解引用指標之前確信它非 0
if ( px != 0 )
 
// 解引用指標
}

另一方面,對於引用參數,函數不需要保證它指向一個對象。引用必須指向一個對象,甚至在我們不希望這樣時也是如此,例如 :
class Type { };
void operate( const Type& p1, const Type& p2 );
int main() {
Type obj1;
// 設定 obj1 為某個值
// 錯誤: 引用參數的實參不能為 0
Type obj2 = operate( obj1, 0 );
}

如果一個參數可能在函數中指向不同的對象,或者這個參數可能不指向任何對象,則必須使用指標參數 。

 

引用參數的一個重要用法是:它允許我們在有效地實現重載操作符的同時,還能保證用法的直觀性。

以Matrix 對象的加法重載操作符來舉例:

Matrix // 加法返回一個 Matrix 對象
operator+( // 重載操作符的名字
Matrix m1, // 操作符左運算元的類型
Matrix m2 // 操作符右運算元的類型
)
{
Matrix result;
// do the computation in result
return result;
}

可以這樣使用:

Matrix  a,b,c;  a = b+c; a+b+c;

但是operator+是按值傳遞,效率較低,如果我們改成指標參數:

Matrix operator+( Matrix *m1, Matrix *m2 )

{
Matrix result;
 
// 在 result 中計算
return result;
}

雖然在獲得了效率,但在使用時將出現這樣的代碼:a = &b +&c  和&( &a+&b)+&c;顯然並不友好。

下面是 Matrix類的重載加法操作符的修訂版本 
// 使用引用參數的新實現
Matrix operator+( const Matrix &m1, const Matrix &m2 )
{
Matrix result;
// 在 result 中進行計算
return result;
}
該實現支援如下形式的 Matrix對象的加法 
a + b + c

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.