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