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=0int c,char d=’a’);     //不正确
void fun2(float a,int c,int b=0, char d=’a’);     //正确

在使用带有默认参数的函数时有两点要注意:
(1)如果函数的定义在函数调用之前,则应在函数定义中给出默认值。如果函数的定义在函数调用之后,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值。
(2)一个函数不能既作为重载函数,又作为有默认参数的函数。因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,出现二义性,系统无法执行。

void fun(int);            //重载函数之一
void fun(intint = 2);     //重载函数之二,带有默认参数
void fun(int = 1int = 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=1int fun(int);
int g(int x;fun(a)); //OK,允许默认值为函数

默认值不可以是局部变量,因为默认参数的函数调用是在编译时确定的,而局部变量的位置与值在编译时均无法确定。

例如:

int main()
{
    int i;
    void g(int x=i);  // error C2587: “i”: 非法将局部变量作为默认参数
    return 0;
}

 

posted @ 2019-03-19 13:40  王陸  阅读(6617)  评论(0编辑  收藏  举报