Loading

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一样,是一种模板库类型,使用时必须说明所含元素的类型

  • 支持的操作

    image-20220122104443210

  • 例子

    #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
    */
    
posted @ 2022-02-20 08:17  咪啪魔女  阅读(38)  评论(0编辑  收藏  举报