C++ 函数 函数的重载 有默认参数的函数
函数的重载
C++允许用同一函数名定义多个函数,这些函数的参数个数和参数类型不同。这就是函数的重载(function overloading)。
int max1(int a,int b, int c); double max2(double a,double b,double c); long max3(long a,long b,long c);
#include <iostream> using namespace std; int main( ) { int max(int a,int b,int c); //函数声明 int max(int a,int b); //函数声明 int a=8,b=-12,c=27; cout<<″max(a,b,c)=″<<max(a,b,c)<<endl; cout<<″max(a,b)=″<<max(a,b)<<endl; } int max(int a,int b,int c) //求3个整数中的最大者 { if(b>a) a=b; if(c>a) a=c; return a; } int max(int a,int b) //求两个整数中的最大者 { if(a>b) return a; else return b; }
参数的个数和类型可以都不同。但不能只有函数的类型不同而参数的个数和类型相同。
也就是说重载与否是由参数决定的,而不是返回值决定!!!
这里引入一个概念:
函数签名:函数的名称及其参数类型组合在一起,就定义了一个唯一的特性,称为函数签名。(不包括返回类型)
c++要求重载函数具有不同的签名。返回类型不是函数签名的一部分。
C++ requires that overloaded functions have distinct signature.The return type is not part of a function’s signature.
例如:
int main() { int f(int); long f(int); // error C2556: “long f(int)”: 重载函数与“int f(int)”只是在返回类型上不同 void f(int); // error C2556: “void f(int)”: 重载函数与“int f(int)”只是在返回类型上不同 return 0; }
下面介绍重载中的二义性问题:
如果两个不同宽度的数据类型进行运算时,编译器会尽可能地在不丢失数据的情况下将它们类型统一。若float和double运算时,如果不显式地指定为float型,会自动转换成double型进行计算。一个整数类型int和一个浮点类型float运算时,如果不显式地指定为int型,C++会先将整数转换成浮点数。
int main() { float x = 2.1f; float y = 2.1; //warning C4305: “初始化”: 从“double”到“float”截断 return 0; }
上述 语句中float y=2.1 我们以为它是一个float类型,但编译器却把它认为是double(因为小数默认是double型),所以给出了警示信息,一般要定义float类型,则应该改成2.1f。
通常编译器会按照返回类型、参数类型、参数数量区 区别调用哪个重载函数,但有时候,数据类型自动转换机制会使编译器进入死胡同。
float fun(float a); double fun(double a); int main() { float x; x = fun(5.1); x = fun(5); // error C2668: “fun”: 对重载函数的调用不明确 return 0; }
在这里编译器不知道应该讲x=fun(5)转换成float还是double。
有默认参数的函数
一般情况下,在函数调用时形参从实参那里取得值,因此实参的个数应与形参相同。C++允许在定义函数时给其中的某个或某些形式参数指定默认值,这样,当发生函数调用时,如果省略了对应位置上的实参的值时,则在执行被调函数时,以该形参的默认值进行运算。有时多次调用同一函数时用同样的实参,给形参一个默认值,这样形参就不必一定要从实参取值了。如有一函数声明
float area(float r=6.5); area( ); //相当于area(6.5);
如果不想使形参取此默认值,则通过实参另行给出
area(7.5); //形参得到的值为7.5,而不是6.5
实参与形参的结合是从左至右顺序进行的。因此指定默认值的参数必须放在形参表列中的最右端,否则出错。例如:
void fun1(float a,int b=0,int c,char d=’a’); //不正确 void fun2(float a,int c,int b=0, char d=’a’); //正确
在使用带有默认参数的函数时有两点要注意:
(1)如果函数的定义在函数调用之前,则应在函数定义中给出默认值。如果函数的定义在函数调用之后,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值。
(2)一个函数不能既作为重载函数,又作为有默认参数的函数。因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,出现二义性,系统无法执行。
void fun(int); //重载函数之一 void fun(int,int = 2); //重载函数之二,带有默认参数 void fun(int = 1,int = 2); //重载函数之三,带有默认参数 fun(3); //error: 到底调用3个重载函数中的哪个? fun(4,5) //error:到底调用后面2个重载函数的哪个?
默认参数一般在函数声明中提供。如果程序中既有函数的声明又有函数的定义时,则定义函数时不允许再定义参数的默认值。
void fun(int x = 0,int y = 0); void main() {} void fun(int x = 0, int y = 0) { } // error C2572: “fun”: 重定义默认参数 : 参数 2 // error C2572: “fun”: 重定义默认参数 : 参数 1
默认值可以是全局变量、全局常量,甚至是一个函数。例如:
int a=1; int fun(int); int g(int x;fun(a)); //OK,允许默认值为函数
默认值不可以是局部变量,因为默认参数的函数调用是在编译时确定的,而局部变量的位置与值在编译时均无法确定。
例如:
int main() { int i; void g(int x=i); // error C2587: “i”: 非法将局部变量作为默认参数 return 0; }