彻底理清重载函数匹配

前言

前面我们讲到了《什么是函数重载?》,有了函数重载之后,就需要确定某次调用需要选用哪个函数。这个过程可以称之为函数匹配或者重载确定。大多数情况下,我们都很容易能够确定某次调用需要选用哪个函数,但事实上不尽然。但通过本文将彻底理清重载函数匹配

匹配过程

为便于说明,将函数匹配分为三个阶段,确定候选函数,确定可行函数,确定最佳匹配函数。

确定候选函数

候选函数也就是和被调用的函数同名,并且其声明在调用点可见。举个简单的例子。
假设有两个文件,1.cpp和2.cpp,内容分别如下:
1.cpp:

//函数1void f(int a,short b){cout<<"func0"<<endl;}

2.cpp:

 #include<iostream>using namespace std;//函数2void f(int a,double b){cout<<"func1"<<endl;}//函数3
void f(int a, int b){cout<< "func2"<<endl;}//函数4void f1(){cout<<"func3"<<endl;}int main(){f(3,4.5);return 0;}

在这里,候选函数其实只有两个,其中第一个函数在其调用点不可见,而第四个函数和被调用的函数不同名,因此这两个都不是候选函数。

确定可行函数

可行函数指的是本次调用传入的实参能够被候选函数使用。它要满足两个条件, 一是形参数量和实参数量相同,二是每个实参的类型和对应形参类型相同或者能够转换成形参的类型。

还是前面的例子,实参的个数和类型与第二个函数完全匹配,而在经过算术转换之后,也能够与第三个函数匹配。

确定最佳匹配函数

最佳匹配的函数是最终调用的。最佳匹配最基本的思想是认为,实参类型越接近,它们就越匹配。还是前面的例子,实参要与第三个函数匹配,需要进行算术转换,而与第二个函数完全匹配,因此第二个函数是最佳匹配函数。最终的运行结果如下:

 func1

最佳匹配原则

一般来说,精确匹配肯定比需要类型转换的匹配要更好,但是当形参有多个,并且无法完全精确匹配的时候,要确定最佳匹配函数就有点困难了。
但是有下面的原则:

  • 函数的每个实参的匹配都不能比其他可行函数更差

  • 函数至少有一个实参的匹配要比其他可行函数更好

那么问题又来了,什么是更好,什么又是更差呢?编译器将实参类型到形参类型的转换划分了等级:

  • 1.精确匹配,包括实参类型和形参类型相同,实参从数组或函数转换成对应的指针类型,向实参添加顶层const或从实参删除顶层const

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

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

  • 4.通过算数类型转换实现的匹配

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

等级越靠前,匹配也就越好。接下来对上面的内容做一些解释。

精确匹配

精确匹配比较容易理解。关于顶层const问题,可以参考《什么是函数重载?》

通过const转换实现的匹配

所谓通过const转换实现的匹配,指的是通过加const限定词,能够与可行函数精确匹配。例如:

#include <iostream>
using namespace std;
//函数1
/*
int f(string &a)
{cout<<"call function 1"<<endl;return 0;
}*/
//函数2
int f(const string &a)
{cout<<"call function 2"<<endl;return 0;
}
int main()
{string test = "test";f(test);return 0;
}

在这里,test可以通过const转换,从而匹配函数2,将能够找到最佳匹配函数2(当前情况它也只有一个可选了)。
运行结果如下:

call function 2                                   

如果把函数1的注释去掉再运行,就会发现,虽然第一个调用既能匹配函数1,也能匹配函数2,但是由于匹配函数2的时候,需要const转换,因此比精确匹配要差,最终,它会调用函数1。
去掉函数1的注释后,运行结果如下:

call function 1                                      

通过类型提升实现的匹配

关于类型提升,这里不多做介绍。简单说明类型提升规则:

  • float将提升到double

  • char、short和相应的signed、unsigned类型将提升到int

我们来看一个示例:

#include <iostream>
using namespace std;
//函数1
/*
int f(short a)
{cout<<"call function 1"<<endl;return 0;
}*/
//函数2
int f(  int a)
{cout<<"call function 2"<<endl;return 0;
}
int main()
{short a = 2;f(a);return 0;
}

同样地,我们暂时把函数1注释掉。由于a是short类型,但是通过类型提升,可以转换为int,因为它也能调用函数2。运行结果如下:

call function 2

但去掉函数1注释后,由于精确匹配优于通过类型提升的匹配,因此将会调用函数1,运行结果如下:

call function 1

通过算术类型转换实现的匹配

short int和float,double等之间的转换,都是算术类型之间的转换。我们仍然来看一个例子:

#include <iostream>
using namespace std;
//函数1
int f(int a)
{cout<<"call function 1"<<endl;return 0;
}
//函数2
int f(double a)
{cout<<"call function 2"<<endl;return 0;
}
int main()
{short a = 2;f(a);return 0;
}

在这里,short类型的a既可以通过类型提升转换为int,也可以通过算术类型转换成为double。这个时候,哪个才是最佳匹配呢?我们看运行结果:

call function 1

对于这个结果,并不意外,因为前面我们已经说到,通过类型提升的转换是优于算术转换的,因而函数1是它的最佳匹配函数。

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

这里不多做介绍。我们也很容易理解。诸如父类和子类之间的转换都是如此。

二义性示例

前面基本能够找到最佳匹配,我们来看一个有多个可行函数,最后却没有最佳匹配的情况。

 #include<iostream>using namespace std;//函数1void f(double a,int b){cout<<"function 1"<<endl;}//函数2void f(int a,double b){cout<<"function 2"<<endl;}int main(){f(1,1);return 0;}

函数1和函数2都是可行函数,但它们都没有在任意一个参数上比对方更好,因此将会产生二义性,编译时将会报错:

error: call of overloaded ‘f(int, int)’ is ambiguous

总结

  • 调用重载函数时,应当避免强制类型转换。

  • 设计重载函数时应避免可能产生的二义性。

  • 如果无法找到可行函数,编译器将报错。

  • 设计重载函数的时候,希望避免需要用到上面的知识,而在定位问题时能够利用上面的知识很快定位问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/462911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPRS底层API(转)

【API函数】&#xff1a;a)ConnMgrApiReadyEvent&#xff08;&#xff09;函数函数原型&#xff1a;HANDLE WINAPI ConnMgrApiReadyEvent();利用此函数来我们可以返回一个连接事件的句柄&#xff0c;注意在的得到句柄后要记得及时释放b)ConnMgrConnectionStatus&#xff08;&am…

js和jquery书籍

开始学习js了&#xff0c;找了基本书&#xff0c;留着看。 http://www.cnblogs.com/xiao_luobo/archive/2010/12/03/1895270.html http://blog.csdn.net/rodjohnsondoctor/article/details/7610688 基础类《高效能人士的7个习惯》&#xff08;推荐给所有刚刚进入职场的新人&…

面向对象与软件工程—团队作业1

一、队伍介绍 队伍名称&#xff1a;逍遥此身君子意 队伍编号&#xff1a;1523933 参赛区域&#xff1a;西北赛区 参赛类别&#xff1a;小程序 指导老师&#xff1a;崔亚超 二、队伍成员信息 姓名&#xff1a;凌龙&#xff08;队长&#xff09; 学号&#xff1a;1700802085 班级…

PostgreSQL的核心架构

PostgreSQL的核心架构 注意 本人的博客都迁移到本人自己搭建的博客地址&#xff0c;通过此处可查看。 应用程序的访问接口 1. 访问接口总体图 进程及内存结构 1. 进程和内存结构图 主进程&#xff1a;Postmaster进程 辅助进程&#xff1a;SysLogger&#xff08;系统日志&a…

BUG: Setup Was Unable to Create a DCOM User Account Error Message in Visual Studio 6.0

今天在安装VS 6.0时&#xff0c;遇见这个问题&#xff1a;Setup was unable to create a DCOM user account in order to register <path>&#xff3c;valec.exe后来找到原来是VS的一个Bug。贴出微软的原文&#xff1a;BUG: "Setup Was Unable to Create a DCOM Use…

研究下

渗透测试: http://www.cnblogs.com/hyddd/archive/2009/03/22/1419104.html ldap: http://waringid.blog.51cto.com/65148/79648/

线程属性 pthread_attr_t

参考资料&#xff1a; https://blog.csdn.net/hudashi/article/details/7709413 Posix线程中的线程属性pthread_attr_t主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。在pthread_create中&#xff0c;把第二个参数设置为NULL的话&#xff0c;将采用默认的属性配置…

如何让new操作符只构造,不申请内存

问题 c中的new操作符 通常完成两个工作 分配内存及调用相应的构造函数。 请问&#xff1a; 如何让new操作符不分配内存&#xff0c;只调用构造函数&#xff1f; 这样的用法有什么用&#xff1f; placement new的含义 placement new可以实现不分配内存&#xff0c;只调用…

Linux 下的多线程下载工具

2019独角兽企业重金招聘Python工程师标准>>> 最先用的是 Axel&#xff08;http://axel.alioth.debian.org/&#xff09;&#xff0c;功能还可以&#xff0c;不过下载文件最多支持到 2GB&#xff0c;再大的文件就不能下载了&#xff0c;真变态&#xff01; aget&…

Launcher结构之home screen

今天刚刚知道如果你的Eclipse里面的工程指向服务器里面的源码记住千万不能在Eclipse里编译~~会在服务器上的源码里多处很多的中间件这样make不了只能清除那些中间件才能编译比较麻烦 Home screen可以说是一个手机的最重要应用&#xff0c;就像一个门户网站的首页&#xff0c;直…

Python_迭代器和生成器的复习_38

迭代器和生成器 迭代器&#xff1a; 双下方法&#xff1a;很少直接调用的方法&#xff0c;一般情况下&#xff0c;是通过其他方法触发的 可迭代的协议——可迭代协议 含有__iter__ 的方法 (__iter__ in dir(数据)) 可迭代的一定可以被for循环 迭代器协议&#xff1a;含有 __ite…

Elasticsearch是如何做到快速索引的

最近在参与一个基于Elasticsearch作为底层数据框架提供大数据量(亿级)的实时统计查询的方案设计工作&#xff0c;花了些时间学习Elasticsearch的基础理论知识&#xff0c;整理了一下&#xff0c;希望能对Elasticsearch感兴趣/想了解的同学有所帮助。 同时也希望有发现内容不正确…

第13届年度Webby奖采用Silverlight / 13th Annual Webby Awards powered by Silverlight

13th Annual Webby Awards powered by Silverlight 第13届年度Webby奖采用Silverlight 原文连接&#xff1a;http://team.silverlight.net/case-study/13th-annual-webby-awards-powered-by-silverlight/ 原文分类&#xff1a;Case Study&#xff08;案例学习&#xff09; 原文…

纯C日志函数库 zlog

zlog - 纯C日志函数库 - 开源中国纯C日志函数库 zlog分享到 新浪微博腾讯微博已用 10收藏92参加 OSC 应用开发大赛&#xff0c;拿 Nexus 4 手机 星星之火&#xff0c;可以燎原zlog是一个高性能、线程安全、灵活、概念清晰的纯C日志函数库。事实上&#xff0c;在C的世界里面没…

[十二省联考2019]字符串问题 后缀自动机 + 拓扑排序 + 最长路 + 倍增

题目描述&#xff1a;给定一个长串 $S$&#xff0c;给定若干 $S$ 的子串 $a_{i}$, $b_{i}$&#xff0c;再给出一些 $a$ 串和 $b$ 串的支配关系. 构造一个长度最长的字符串&#xff0c;使得&#xff1a;字符串只由 $a_{i}$ 组成.当且仅当 $a_{i}$ 所支配的一个串 $b_{i}$ 为 $a_…

分布式事务2PC、3PC模型

工作中使用最多的是本地事务&#xff0c;但是在对单一项目拆分为 SOA、微服务之后&#xff0c;就会牵扯出分布式事务场景 文章以分布式事务为主线展开说明&#xff0c;并且针对 2PC、3PC 算法进行详细的讲解&#xff0c;最后通过一个 Demo 来更深入掌握分布式事务&#xff0c;…

c# datatable用法总结

在项目中经常用到DataTable,如果DataTable使用得当&#xff0c;不仅能使程序简洁实用&#xff0c;而且能够提高性能&#xff0c;达到事半功倍的效果&#xff0c;现对DataTable的使用技巧进行一下总结。 一、DataTable简介 (1)构造函数 DataTable() 不带参数初始化DataT…

Python学习之路——装饰器

开放封闭原则&#xff1a;不改变调用方式与源代码上增加功能 1.不能修改被装饰对象(函数)的源代码&#xff08;封闭&#xff09; 2.不能更改被修饰对象(函数)的调用方式&#xff0c;且能达到增加功能的效果&#xff08;开放&#xff09;View Code装饰器 # 把要被装饰的函数作为…

通断时间面积法

背景&#xff1a; 来 源&#xff1a; 通断时间面积法是入选《供热计量技术规程》JGJ173-2009的一种热量分摊计量方法实现分户计量的一种计量方法。由清华大学建筑节能研究中心江亿院士提出。 简 称 ( 俗称 )&#xff1a;&#xff08;1&#xff09;“时温法”&#xff08;2&a…

C++ std::move()和完美转发

std::move()、std::forward<T>、模板类型推断分析 引用折叠原则和完美转发是有联系的&#xff0c;可以说后者是基于前者的某些特性实现的&#xff0c;具体来看一下。 要理解完美转发&#xff0c;需要了解两个知识点&#xff1a; 引用折叠原则&#xff08;Reference colla…