函数基础
函数组成
下面用一个简单的函数介绍一下函数组成。
int fact(int val) //这是一个参数为一个int型,返回值类型也为int的函数
{
int ret=1; //在函数内定义的参数是一个局部对象
while(val>1)
ret*=val--;
return ret; //返回值为int型
}
形参和实参
实参是形参的初始值,在函数调用时,会利用实参来对形参进行初始化。一个实参对应一个形参,若调用时参数不一致就会导致调用失败。实参的类型必须和形参相同或是可以转换为形参的类型
返回值
除去void类型的函数,其他函数必须在函数结束时调用return语句返回一个值。这个值将会用来初始化一个用来返回而临时变量,所以返回值应与函数的返回值类型相同或是可以转换成函数的返回值类型。
局部变量
形参和函数体内部定义的变量被叫做局部变量,局部变量只在函数的作用域可见,同时,函数内部的局部变量还会隐藏外部定义的同名变量。
自动对象
指只在块作用域内存在的对象。在离开块的时候自动销毁。普通的局部变量是一种自动对象。
传参方式
在c++中函数分为值传递和引用传递。当形参为引用类型时,函数被叫做引用传参。在c++中,可以通过传入指针或引用的方式在函数内修改多个变量。
函数声明
在使用函数前我们必须先对函数进行声明,函数声明包括(返回值类型,函数名,形参列表)三部分。一般来说,我们希望将函数声明在头文件内。
函数特性
默认实参
有一个形参的值在函数中多次使用,并且我们又不想修改它的值,我们就可以将它声明成默认实参。
int exmple(int a,int b,int c=0) //c为默认实数
{
int sum=a+b+c;
return sum;
}
当我们调用exmple(1,2)时,相当于exmple(1,2,0)
值得注意的是当一个形参被声明为默认参数时,其后的参数都必须是默认实参。
如函数声明为int exmple(int a=0,int b,int c=0);是不合法的,因为a是默认实参而b不是。
内联函数
调用函数一般比直接操作会更慢一些;但若将一个多次使用的函数直接展开又显得多余。所以我们可以将函数声明成内联函数,通常就是将它在每个调用点内联的展开。
例如
inline int exmple(int a,int b,int c=0) //c为默认实数
{
int sum=a+b+c;
return sum;
}
注意:1.内联机制用于优化规模小,流程直接,频繁调用的函数。
2.通常内联说明只是向编译器发出的请求,编译器可以忽略。
constexpr函数
constexpr函数是指可以用于常量表达式的函数。
constexpr函数的定义方式与普通函数相似,但需要满足函数的返回值类型以及所有的形参类型必须都是字面值类型。
constexpr size_t scale(size_t cmt) {return new_sz()*cnt;)
constexpr内允许有其他语句,但需要在调用函数时不执行。(如空语句,类型别名)
函数重载
C++允许在同一个作用域中出现了多个名字相同但是形参不同的函数,它们被称作重载函数。在执行这些函数时,编译器会根据传入的实参类型来选择调用哪个函数。对于重载函数来说,他们必须在形参数量或类型上有所不同。
如下形式
void print(const char *cp);
void print(const int *beg,const int *end);
void print(const int ina[],size_t size);
值得注意的是:
1.不允许两个函数除了返回值类型外其他所有要素相同.
2.顶层的const不影响函数对象。
//重复定义了!
void fact(int);
void fact(const int);
函数匹配
函数调用的结果有三:
1.最佳匹配。
2.无匹配。
3.二义性调用。
函数调用的第一步是寻找候选函数。候选函数的特征是1.与所调函数名相同,2.当前调用点可见(作用域)。
第二步是从候选函数中找出可行函数。可行函数的特征是调用时传入实参与函数形参数量相同,且类型相同或可转换成形参类型。
最佳匹配:实参类型与形参类型越接近,他们匹配的越好。
含有多个形参的函数匹配:
如下函数调用会出现二义性调用:
void exmple(double,int);//函数原型
void exmple(int,double);
exmple(1,1)//当这样调用时两个函数都是可用函数,且都只有一个参数完全匹配,所以会出现二义性调用。