C++中函数重载

首先,函数为什么能够重载?

因为我们在编译和链接的过程中,通过名字粉碎技术,给同名函数起了不同的名字,新的名字要把它的类型、参数作为它们名称的一部分,在源码上我们看到的是相同的函数名,但是在编译和链接的过程中,由于我们把参数列表作为函数名的一部分,那么函数名实际上是不一样的,可以进行区分。

1.C语言实现int,double,char类型的比较大小函数

int my_max_i(int a,int b){return a>b?a:b;}
double my_max_d(double a,double b){return a>b?a:b;}
char my_max_c(char a,char b){return a>b?a:b;}

这些函数都执行了相同的一般性动作;都返回两个形参中的最大值;从用户的角度来看, 只有一种操作,就是判断最大值,至于怎样完成其细节, 函数的用户一点也不关心。
这种词汇上的复杂性不是”判断参数中的最大值“问题本身固有的,而是反映了程序设计环境的一 种局限性:在同一个域中出现的名字必须指向一 个唯实体(函数体)。
这种复杂性给程序员带来了一个实际问题,他们必须记住或查找每一个函数名字。
函数重载把程序员从这种词汇复杂性中解放出来。

2.函数重载的概念:

在C++中可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或参数类型相同而参数的个数不同,称为函数重载。

//my_max + 参数表
int my_max(int a,int b)
{
    return a>b?a:b;
}
double my_max(double a,double b)
{
    return a>b?a:b;
}
char my_max(char a,char b)
{
    return a>b?a:b;
}
//每个同名函数的参数表是唯一的
int main()
{
    int ix=my_max(12,23);
    double dx=my_max(12.23,34,45);
    char chx=my_max('a','b');
    
    return 0;
}

编译器的工作:

​ 当一个函数名在同一个域中被声明多次时,编译器按如下步骤解释第二个(以及后续的)声明。
​ 如果两个函数的参数表中的参数个数或类型或顺序不同,则认为这两个函数是重载。

例如:

//重载函数,这种力求避免
void print(int a,char b)
void print(char a,int b)`

3.判断函数重载的规则:

1)如果两个函数的参数表相同,但是返回类型不同,会被标记为编译错误:函数的重复声明。

int my_max(int a,int b)
{
    return a>b?a:b;
}
unsigned int my_max(int a,int b)//error
{
    return a>b?a:b;
}
int main()
{
    int ix=my_max(12,23);
    unsigned int ui=my_max(12,23);//error
    
    return 0;
}

2)参数表的比较过程与形参名无关,只比较形参的类型、个数以及顺序

//声明同一个函数
int my_add(int a,iny b);

int my_add(int x,int y);

3)如果在两个函数的参数表中,只有缺省实参不同,则第二个声明被视为第一个的重复声明。

void Print(int *br,int n);

void Print(int *br,int len=10);

4)typedef名为现有的数据提供了一个替换名,它没有创建一个新类型,因此,如果两个函数的参数表区别只在于一个使用了typedef,而另一个使用了与typedef相应的类型,则该参数表被视为相同的参数表。

typedef unsigned int u_int;
int Print(u_int a);
int Print(unsigned int b);

5)当一个形参类型有const或volatile修饰时,如果形参是按值传递方式定义,在识别函数声明是否相同时,并不考虑const和volatile修饰符。

void fun(int a){}

void fun(const int a){}

6)当一个形参类型有const或volatile修饰时,如果形参定义指针或者引用时,在识别函数声明是否相同时,就需要考虑const和volatile修饰符。

void fun(int *p){}
void fun(const int *p){}

void func(int &a){}
void func(const int &a){}

int main()
{
    int a=10;
    const int b=20;
    fun(&a);//void fun(int *p)
    fun(&b);//void fun(const int *p)
    
    int x=10;
    func(x);//void func(int &a)
    func(10);//void func(const int &a)
}

7)注意函数调用的二义性:
如果在两个函数的参数表中,形参类型相同,而形参个数不同,形参默认值将会影响函数的重载。

//ok
void fun(int a){}

void fun(int a,int b){}


int main()
{
    fun(12);//void fun(int a)
    fun(12,23);//void fun(int a,int b)
}
//error 二义性
void fun(int a){}

void fun(int a,int b=10){}//实参可以给一个也可以给两个

int main()
{
    fun(12);//error,出现二义性
    fun(12,23);
}

8)函数重载解析的步骤如下

(1)确定函数调用考虑的重载函数的集合,确定函数调用中实参表的属性;

(2)从重载函数集合中选择函数,该函数可以在(给出实参个数和类型)的情况下可以调用函数;

(3)选择与调用最匹配的函数。

void print(int a){}
void print(int &b){}
void print(const int &c){}
int main()
{
    int x=10;
    const int y=20;
    print(x);//最佳匹配:print(int &b)//如果没有普通引用 print(const int &c)
    
    //void print(int a){}
    //void print(int &b){}
    //print(x)以上两个均可调用,因此当两者同时出现时会出现二义性,屏蔽第一个函数,编译能通过
   
    print(y);//最佳匹配:print(const int &c),如果没有常引用函数其它函数均不能与其匹配
    
    //屏蔽第一个和第二个函数,print(x);print(y);两条语句均能便于通过
    //但是如果屏蔽第一个和第三个函数,print(x);编译能够通过;print(y);编译不能通过
    return 0;
}
void func(int *p){}
void func(const int *s){}
int main()
{
    int x=10;
    const int y=20;
    func(&x);//最佳匹配:func(int *p)//如果没有普通指针 func(const int *s)

   func(&y);//最佳匹配:func(const int *s),如果没有常指针函数其它函数均不能与其匹配
    
    //屏蔽第一个函数,func(&x);func(&y);两条语句均能便于通过
    //但是如果屏蔽第二个函数,func(&x);编译能够通过;func(&y);编译不能通过
    return 0;
}
void fun(int *p){}//1
void fun(const int *s){}//2
void fun(int * const r){}//3
//1,3是相同的函数声明,而2与其他两个不同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值