《C++primer》第五版笔记:函数重载

 

定义

作用于同一作用域内的几个函数名字相同但是形参列表不同,我们称之为重载函数。

规则

1.对于重载函数来说,应该在形参数量或形参类型上有所不同。

2.不允许两个函数除了返回类型外其他的要素都相同

3.一个拥有顶层const的形参无法和另一个没有顶层const的形参区分开来。另一方面,如果形参是某种类型的指针或引用,则通过其指向的是常量对象还是非常量对象可以实现重载,此时const是底层的。

编译器可以通过实参是否是常量来推断应该调用哪个函数。因为const不能转化为其他类型,而非常量可以转化为const类型。当有一个常量版本和一个非常量版本,我们传递一个const只能用常量版本,而传递一个非常量时,编译器会优先选择非常量版本的函数。

const_cast和重载

举个栗子:

// 比较两个string对象的长度,返回较短的那个引用
const string &shorterString(const string &s1,const string &s2)
{
    return s1.size()<=s2.size() ? s1 : s2;
}


string &shorterString(string &s1,string &s2)
{
    auto &r=shorterString(const_cast<const string &>(s1),
                          const_cast<const string &>(s2));
    return const_cast<string &>(r);
}

这里的一些细节:

1.const_cast加上和去除底层const

2.在非常量的版本中调用常量的版本,得到的返回是常量的,而本身s1,s2是非常量的,所以去掉r的底层const是没有关系的

调用重载的函数

现在需要掌握的三种情况(可能书后边也有多讲吧):

1.编译器找到一个与实参最佳匹配的函数,生成调用该函数的代码

2.找不到任何一个函数与调用的实参匹配,编译器发出无匹配的错误信息

3.有多于一个函数可以匹配,但是每一个都不是最佳选择,此时也将发生错误,称为二义性调用(ambiguous call)

重载与作用域

一旦在作用域中找到了所需的名字,编译器就会忽略外层作用域中的同名实体,剩下的工作就是检查函数调用是否有效了(P210)

函数匹配

具体见原书P217

以下面这组函数及其调用为例:

void f();
void f(int);
void f(int,int);
void f(double,double=3.14);
f(5.6);//调用void f(double,double)

确定候选函数和可行函数

函数匹配的第一步是选定本次调用对应的重载函数集,集合中的函数称为候选函数。候选函数具备两个特征:一是与被调用的函数同名,二是其声明在调用点可见。在这个例子中,有四个名为f的候选函数。

第二步考察本次调用中的形参,然后从调用函数中选出能被这组实参调用的函数,这些新选出的函数称为可行函数。可行函数有两个特征:一是其形参数量与本次调用提供的实参数量相等,二是每个实参的类型与对应的形参类型相同,或者能转换成形参的类型。

实参数量判断:

我们能根据实参的数量排除两个。不使用形参的函数和使用两个int的函数。

使用一个int形参的函数和使用两个double形参的函数是可行的,它们都能用一个实参调用。

实参类型判断:

显然,两个double形参的函数更加匹配

note:如果没有找到可行函数,编译器将报告无匹配函数的错误

寻找最佳匹配

函数匹配的第三步是从可行函数中选择与本次调用最匹配的函数。那么什么是最匹配呢,当然是指形参类型和实参类型最匹配的可行函数,关于最匹配的细节,编译器将实参类型到形参类型的转换划分成几个等级,具体排序如下所示:

1.精确匹配:

 实参类型和形参类型相同

实参从数组类型或函数类型转换成对于的指针类型

向实参添加顶层const或删除顶层const

2.通过const转换实现的匹配

3.通过类型提升实现的匹配

4.通过算数类型或指针转换实现的匹配

5.通过类类型转换实现的匹配

含有多个形参的函数匹配

当实参的数量有两个或者更多时,函数匹配就比较复杂了。对于前面哪些名为f的函数,我们来分析(42,2.56);会发生什么情况。此例中f(int,int)和f(double,double)都是可行函数。接下来,编译器将依次检查每个实参确定哪个函数是最佳匹配。如果有且只有一个函数满足下列条件,则匹配成功:

1.该函数每个实参的匹配都不劣于其他可行函数需要的匹配

2.至少有一个实参的匹配优于其他可行函数提供的匹配

如果检查了所有形参后没有一个函数脱颖而出,那么该调用是错误的。编译器将报告二义性调用的信息。

f(int,int)在第一个实参上比f(double,double)更好,而f(double,double)在第二个实参上比f(int,int)更好,所以编译器最终因为这个调用具有二义性而拒绝其请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值