C++ Primer 参数传递

欢迎阅读我的 【C++Primer】专栏

专栏简介:本专栏主要面向C++初学者,解释C++的一些基本概念和基础语言特性,涉及C++标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级程序设计技术。希望对读者有帮助!

在这里插入图片描述
在这里插入图片描述

6.2 参数传递

每次调用函数时都会重新创建它的形参,并用传入的实参对形参进行初始化。

形参初始化的机理与变量初始化一样。

和其他变量一样,形参的类型决定了形参和实参交互的方式。如果形参是引用类型,它将绑定到对应的实参上;否则,将实参的值拷贝后赋给形参。

当形参是引用类型时,我们说它对应的实参被引用传递(passed by reference)或者函数被传引用调用(called by reference)。和其他引用一样,引用形参也是它绑定的对象的别名;也就是说,引用形参是它对应的实参的别名。

当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象。我们说这样的实参被值传递(passed by value)或者函数被传值调用(called by value)。

传值参数

当初始化一个非引用类型的变量时,初始值被拷贝给变量。此时,对变量的改动不会影响初始值:

int n = 0;// int类型的初始变量
int i = n;//工是n的值的副本
i = 42; //i的值改变;n的值不变

传值参数的机理完全一样,函数对形参做的所有操作都不会影响实参。例如,在fact函数内对变量val执行递减操作:

ret* = val--; // 将val的值域减1

尽管fact函数改变了val的值,但是这个改动不会影响传入fact的实参.调用fact(i)不会改变i的值。

指针形参

指针的行为和其他非引用类型一样。当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后,两个指针是不同的指针。因为指针使我们可以间接地访问它所指的对象,所以通过指针可以修改它所指对象的值:

int n = 0,i = 42;
int *p = &n,*q = &i; //p指向n; q指向i
*p = 42; //n的值改变;P不变
p=q; //p现在指向了i;但是i和n的值都不变

指针形参的行为与之类似:

//该函数接受一个指针,然后将指针所指的值置为0
void reset(int*ip)
{
   
    *ip=03//改变指针ip所指对象的值
    ip=0//只改变了ip的局部拷贝,实参未被改变
}

调用reset函数之后,实参所指的对象被置为0,但是实参本身并没有改变:

int i = 42;
reset(&i);                  //改变i的值而非i的地址
cout<<"i = "<< i << endl;   //输出i=0

熟悉C的程序员常常使用指针类型的形参访问函数外部的对象,在C++语言中,建议使用引用类型的形参替代指针。

传引用参数

回忆过去所学的知识,我们知道对于引用的操作实际上是作用在引用所引的对象上

int n = 0,i=42;
int&r = n; //i绑定了n(即i是n的另一个名字)
i=423;//现在n的值是42
r = i; //现在n的值和i相同
i = r; //i的值和n相同

引用形参的行为与之类似。通过使用引用形参,允许函数改变一个或多个实参的值。举个例子,我们可以改写上一小节的reset程序,使其接受的参数是引用类型而非指针:

//该函数接取一个int对象的引用,然后将对象的值置为0
void reset(int i)//i是传给reset函数的对象的另一个名称
{
   
    i=0; //改变了i所引对象的值
}

和其他引用一样,引用形参绑定初始化它的对象。当调用这一版本的reset函数时,i绑定我们传给函数的int对象,此时改变i也就是改变i所引对象的值。此例中,被改变的对象是传入reset的实参。

调用这一版本的reset函数时,我们直接传入对象而无须传递对象的地址:

int j=42;
reset(j);//了采用传引用方式,它的值被改变
cout<< "j=" << j <<endl;//输出于=0

在上述调用过程中,形参i仅仅是j的又一个名字。在reset内部对i的使用即是对j的使用。

使用引用避免拷贝

拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型(包括IO类型在内)根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。举个例子,我们准备编写一个函数比较两个string对象的长度。因为string对象可能会非常长,所以应该尽量避免直接拷贝它们,这时使用引用形参是比较明智的选择。又因为比较长度无须改变string对象的内容,所以把形参定义成对常量的引用

//比较两个string对象的长度
bool isShorter(const string&s1,const string&s2)
{
   
    return s1.size()<s2.size();
}

当函数无须修改引用形参的值时最好使用常量引用。

加果函就无须改变引用形参的值,最好将其声明为常量引用。

使用引用形参返回额外信息

一个函数只能返回一个值,然而有时函数需要同时返回多个值,引用形参为我们一次返回多个结果提供了有效的途径。举个例子,我们定义一个名为find_char的函数,它返回在string对象中某个指定字符第一次出现的位置。同时,我们也希望函数能返回该字符出现的总次数。

该如何定义函数使得它能够既返回位置也返回出现次数呢?一种方法是定义一个新的数据类型,让它包含位置和数量两个成员。还有另一种更简单的方法,我们可以给函数传入一个额外的引用实参,令其保存守符出现的次数:

//返回s中c第一次出现的位置家引
//引用形参 occeurs 负责统计c出现的总次数
string::size_type find_char(const string&s,char c, string::size_type&occurs){
   
auto ret=s.size();//第一次出现的位置(如果有的话)
oceurs
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值