1. 程式人生 > 其它 >6-2 引數傳遞

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
    */