C++函数基础
函数的调用完成两项工作:一是用实参初始化函数对应的形参,二是将控制权转移给被调用函数,此时主调函数的执行被暂时中断,被调函数开始执行。
当遇到return语句时结束函数执行过程,一是返回return的值(有的话),二是将控制权从被调函数转移向主调函数。实参是形参的初始值,实参的类型必须与对应的形参类型相匹配(或能转化),函数有几个形参,必须提供相同数量的实参,所以形参一定会被初始化。
函数的形参列表
函数的形参列表可以为空,但是不能省略,每个形参都是含有一个声明符的声明。
int f3(int v1,v2) {/* ...*/}//错误
int f4((int v1,int v2) { }//正确
任意两个形参都不能同名,而且函数最外层作用域中的局部变量不能使用与形参一样的名字,形参名可选,但尽量加上。
函数返回类型
函数的返回类型不能是数组类型或函数类型,但可以是指向数组或函数的指针。
函数应该在头文件中声明,在源文件中定义,定义函数的源文件应该把含有函数声明的头文件包含进来。
参数传递
大致分为 引用传递 和 拷贝传递
1. 拷贝传递
一、传值参数
对变量的改动不会影响初始值,即函数对形参的所有操作都不会影响实参。
二、指针形参
指针的行为和其他非引用类型一样。当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后,两个指针是不同的指针,因为指针使我们可以间接访问它所指的对象,所以通过指针可以修改它所指对象的值。
void resrt(int *p)
{
*ip=0;
}
int i=42;
resrt(&i);
cout<<"i= "<<i<<endl;
改变 i 的值而非 i 的地址,即实参所指的对象发生了改变,但是实参本身没有发生改变。
2.传引用参数
在C++语言中,建议使用引用类型的形参代替指针。不同于拷贝传递的方式 实参的值拷贝给形参。引用形参是它对应实参的别名,引用形参将绑定到到对应的实参上。
void reset(int &i)//i是传给rese函数t对象的另一个名字
{
i=0;
}
int j=424;
reset(j);//
cout<<"j= "<<j<<endl;
发现只需直接传入对象而无须传递对象地址
技巧:当拷贝比较大的类类型对象或者容器对象比较低效,甚至有的类类型不支持拷贝操作,应尽量避免直接拷贝他们,这时使用引用形参是比较明智选择。如果函数无须改变引用形参的值,最好将其声明为常量引用。
使用引用形参返回额外信息
一个函数只能返回一个值,然而有时函数需要同时返回多个值,引用形参提供了极大便利。举个例子,我们定义一个名为find_char的函数,它返回在string对象中某个指定字符第一次出现的位置,同时还希望能返回该字符出现的总次数。
解决方案:
1.定义一种数据类型,让它包含位置和数据两个成员
2可以传入一个额外的引用实参,令其保存字符出现次数
.
#include<iostream>
#include<string>
using namespace std;
size_type find_char(const string &a,char c,size_type &occurs)
{
auto ret=s.size();//初始假定ret为一个不可能的值
occurs=0;
for(decltype(ret)i=0;i!=s.size();++i)
{
if(a[i]==c)
{
if(ret==s.size())//说明ret第一次出现
ret=i;//改变ret的值,以后将不会再经历这个if判断
++occurs;//occurs负责统计出现的总次数,隐式返回
}
}
return ret;
}
const形参和实参
当形参是const时,需注意关于顶层const的讨论,如前所述,顶层const作用于对象本身。和其他初始化过程一样,当用实参初始化形参时会忽略掉顶层const.。在重载函数时时,
void fun(const int i) {/* fun能读取i但不能向i写值 */}
void fun(int i){/* */}//错误,重复定义了fun(int)
因为重载函数需要形参列表有明显区别。上面两个实际一样。
我们可以使用非常量初始化一个const对象,但是反过来不行。即转化原则。同时引用必须用同类型的对象,不能使用字面值,求值结果为int的表达式,需要转换的对象或者const int 类型的对象( 不能建立常量的普通引用,可建立变量的常量引用)。
另一方面,我们能传递一个字符串字面值作为find_char的第一个实参,这是因为该函数的引用形参是常量引用,而C++允许我们用字面值初始化常量引用。
尽量使用常量引用
把函数不会改变的形参定义成普通的引用是一种常见错误,这么做带给函数的调用者一种误导,即函数可以修改它实参的值,而且,使用引用而非常量引用限制了函数所能接受的实参类型,就像刚刚看到的,我们不能把const对象或者需要类型转换的对象传递给普通的引用实参。例,若我们将find_char应用改成普通引用,这样调用语句find_char(“hello woeld”,‘o’,ctr); 将发生错误。因为不能接受字面值,只能接受对象。