6-2 引數傳遞
基本介紹
和其他變數一樣,形參的型別決定了形參和實參互動的方式。
- 當形參是引用型別時,我們說它對應的實參被引用傳遞(passed by reference)或者函式被傳引用呼叫(called by reference)。和其他引用一樣,引用形參也是它繫結的物件的別名;也就是說,引用形參是它對應的實參的別名。
- 當實參的值被拷貝給形參時,形參和實參是兩個相互獨立的物件。我們說這樣的實參被值傳遞(passed by value)或者函式被傳值呼叫(called by value)
6.2.1 傳值函式
當初始化一個非引用型別的變數時,初始值被拷貝給變數。
對變數的改動,不會影響原變數
可以用指標間接改變指標所指物件的值,但指標的傳遞過程本身也是值傳遞。
int m = 2;
int n = m; //n拷貝了m的值
n = 3; //對n的改變不會影響m
//用指標的值傳遞間接改變指標所指物件的值 //交換兩數 #include<iostream> using namespace std; void change(int *i, int *j){ int m = *i; *i = *j; *j = m; } int main(){ int i = 2, j = 3; change(&i,&j); cout<<"i = "<<i<<" "<<"j = "<<j<<endl; return 0; }
6.2.2 傳引用函式
引用繫結到了原物件
函式採用引用傳遞時,對引用的操作,實際上是作用在引用所引的物件上
#include<iostream> using namespace std; void change(int &i, int &j){ int m = i; //操作的是原物件 i = j; j = m; } int main(){ int i = 2, j = 3; change(i,j); //i,j被引用傳遞 cout<<"i = "<<i<<" "<<"j = "<<j<<endl; return 0; }
用引用傳遞避免拷貝物件
拷貝大的類型別物件或者容器物件比較低效,甚至有的類型別(包括IO型別在內)根本就不支援拷貝操作。當某種型別不支援拷貝操作時,函式只能通過引用形參訪問該型別的物件。
舉個例子,我們準備編寫一個函式比較兩個string 物件的長度。因為string物件可能會非常長,所以應該儘量避免直接拷貝它們,這時使用引用形參是比較明智的選擇。又因為比較長度無須改變string 物件的內容,所以把形參定義成對常量的引用。
#include<iostream>
using namespace std;
bool isShorter(const string &s1, const string &s2){ //傳入引用來避免拷貝
return s1.size()<s2.size();
}
int main(){
string s1,s2;
cin>>s1>>s2;
cout<<"s1 is shorter than s2 ? : "<<isShorter(s1,s2)<<endl;
return 0;
}
注:常量引用可以被常量初始化而一般引用不能,所以,在不需要改變傳入物件的值,而只是要避免拷貝時,儘量使用常量引用。一方面可以避免對讀者的誤導,也可以保證能想函式傳入常量。
使用引用形參返回額外資訊
一個函式只能返回一個值,然而有時函式需要同時返回多個值,引用形參為我們一次返回多個結果提供了有效的途徑。
舉個例子,我們定義一個名為find_char的函式,它返回在string物件中某個指定字元第一次出現的位置。同時,我們也希望函式能返回該字元出現的總次數。
該如何定義函式使得它能夠既返回位置也返回出現次數呢?一種方法是定義一個新的資料型別,讓它包含位置和數量兩個成員。還有另一種更簡單的方法,我們可以給函式傳入一個額外的引用實參,令其儲存字元出現的次數:
//返回s中c第一次出現的位置索引
//引用形參occurs負責統計c出現的總次數
int find_char(const string &s,char c,int &occurs){
auto ret = s.size() ; //第一次出現的位置(如果有的話)
occurs = 0 ; //設定表示出現次數的形參的值
for(int i = 0 ; i != s.size(); ++i) {
if(s[i] == c){
if (ret == s.size())
ret = i ; //記錄c第一次出現的位置
++occurs; //將出現的次敬加1
}
}
return ret; //出現次數通過occurs隱式地返回
}
呼叫:int index = find_char(s, 'o', ctr);
呼叫完成後,如果string物件中確實存在o,那麼ctr的值就是o出現的次數,index指向o第一次出現的位置;否則如果string物件中沒有o, index等於s.size()
而ctr等於0。
注:string 用常引用避免了複製且不會被修改,occurs採用引用傳遞直接改變源物件的值,作為隱式返回值。
6.2.3 含有可變形參的函式
形參型別相同,數量不定
-
initializer_list<typename>
:一種標準庫型別,和vector一樣,是一種模板庫型別,使用時必須說明所含元素的型別 -
支援的操作
-
例子
#include<iostream> using namespace std; void print(initializer_list<int> li){ for(auto it = li.begin(); it != li.end(); ++it) cout<<*it<<" "; } int main(){ print({1,2,3,4}); cout<<endl; print({1,2,3,4,5}); return 0; } /*輸出結果: 1 2 3 4 1 2 3 4 5 */