把參數聲明成引用,實際上改變了預設的按值傳遞參數的傳遞機制,在按值傳遞時,函數操縱的是實參的本地拷貝。
一、引用參數的三種常見用法:
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