函数模板与同名的非模板函数不可以重载(重载的定义)

关于函数的重载机制,是一个比较复杂的问题,其中涉及到了优先级定义和最佳匹配等问题,如果要阐述清楚,恐怕不是一两篇文章就能说的明白。但是如果掌握了一些常用的“规律”,对于了解程序对重载函数是如何进行选择也有很大的好处,本文尝试将自己理解的知识,结合下面简单的例子简略的说说函数重载机制,文章的摘录部分列出了一些关于程序如何选择重载函数的规则。:)例子如下:#include

大家好,又见面了,我是你们的朋友全栈君。

关于函数的重载机制,是一个比较复杂的问题,其中涉及到了优先级定义和最佳匹配等问题,如果要阐述清楚,恐怕不是一两篇文章就能说的明白。但是如果掌握了一些常用的“规律”,对于了解程序对重载函数是如何进行选择也有很大的好处,本文尝试将自己理解的知识,结合下面简单的例子简略的说说函数重载机制,文章的摘录部分列出了一些关于程序如何选择重载函数的规则。: )

例子如下:

#include <iostream>

 

//non-template function

inline const int& max( const int& a, const int& b )

{

std::cout << “non-template max() is called” << std::endl;

return a < b ? b : a;

}

 

//template function

template < typename T >

inline const T& max( const T& a, const T& b )

{

std::cout << “template max() is called” << std::endl;

return a < b ? b : a;

}

 

int main()

{

::max( 7.0, 42.0 ); //template max() is called

::max( ‘a’‘b’ ); //template max() is called

::max( 7, 42 ); //non-template max() is called

::max<>( 7, 42 ); //template max() is called

::max< double >( 7, 42 ); //template max() is called

::max( ‘a’, 42.7 ); //non-template max() is called

}

程序顺利通过编译,并运行得出结果,说明同名的非函数模板函数和函数模板可以共存。程序会通过优先级和最佳匹配的方式从候选的重载函数集中选定一个函数进行调用(所遵循的规则见后面的摘录部分)。

程序的输出结果见每个函数调用的注释,对于第一和第二个输出结果想必应该没有太多的疑问,程序调用的是函数模板max,下面主要分析其余的输出。

【一】、max( 7, 42 );调用的是非函数模板max()。当其它的要素都相等时,重载机制将优先选择调用非函数模板而不是函数模板【对于这个问题,个人觉得可能是基于如下的原因:进行重载将降低程序的效率,对非函数模板是如此,对于更为复杂的函数模板更是如此(至少还需进行一次实例化),因此重载机制将优先选择调用非函数模板而不是函数模板。】。那些无法跟非函数模板进行最佳匹配的,则调用函数模板的实例化对象,如第一和第二个函数调用。

【二】、max<>( 7, 42 );max( 7, 42 );的唯一区别是前者多了一个模板参数列表,还记得前面笔记中说到的函数模板参数的问题么?<>中的参数用于指定函数模板中,传入的参数类型跟返回值类型,列表中参数的顺序对应于模板中声明的类型的顺序。这里的参数列表为空,但却告诉了编译器,这个函数只在函数模板中选择最佳匹配的函数调用。同样的,max< double >( 7, 42 ); 调用的是函数模板的一个实例化对象,这里指定了模板参数的类型,因此对于传入的值,程序会对其进行一个转换(从int转为double),然后比较大小。

【三】、对于最后一个函数调用max( ‘a’, 42.7 );一开始我认为是调用非函数模板,结果确实也是调用了非函数模板,我的理由是两个参数的类型明显不同,后面看到书上的解释,是这么说的:自动类型转换,只适用于一般函数(即非函数模板)。其实我的理解也没有什么偏差,只是不够深刻。如果觉得‘a'(char)42.7(程序默认为double)相差太大,不好理解上面那句话,试一下这个调用max( ‘a’, 42 );(一般我们都会对charint划上一个隐式的等号,默认char就是int的子集,但事实上还是要经过一个隐式的转换)结果也是调用了非函数模板max()

 

//====================【附录:关于重载的一些说明】====================

这部分的内容主要摘自《c++template》中的附录,有少许语言组织上的改动。另外,《c++primer》中对重载也有比较详细的讨论。

【一】何时会进行重载?

首先,如果是通过函数指针或者成员函数指针来进行调用,就不会进行重载解析,因为究竟调用的是哪个函数是在运行期由指针(实际上所指向对象)来决定的。其次,类似函数的宏不能被重载,因此也不会进行重载解析。

【二】重载是个什么样的过程?

  • 查找名称,从而形成一个初始化的重载集(合)。

  • 如果有必要,会用各种方法对这个集合进行修改(例如,发生模板演绎的时候)。

  • 任何与调用不匹配(即使考虑了隐式转换和缺省实参之后仍然不匹配)的候选函数都从重载集中删除,最后得到的集合就是:可行的候选函数集。

  • 执行重载解析来寻找一个最佳候选函数。如果能找到,则选择这个最佳候选函数;否则,这个调用就是二义性的。

  • 检查这个被选定的最佳候选函数。例如,如果它具有不能访问的私有成员,则可能会给出诊断信息。

【三】关于上面的说到的重载解析,是根据什么原则来选定最佳候选函数?

  • 完美匹配。参数的类型和实参(表达式)的类型相同,或者参数的类型是指向实参类型的引用(也可以增加const或者volatile限定符)。

  • 有细微调整的匹配。如数组转变为指向数组第一个元素的指针,或者添加const,从而让类型为int**的实参匹配类型为int const* const*的参数等。

  • 发生提升的匹配。提升是一种隐式类型转换,它包含把占位少的整数类型(如boolcharshort或者某些枚举)转换为占位多的类型(如intunsigned intlong或者unsigned long),还包括从floatdouble的类型转换。

  • 发生标准转换(类型转换)的匹配。这包含任何种类的标准转型(如intfloat),但并不包含隐式调用的类型转换运算符和单参数构造函数

  • 发生用户自定义转换的匹配。这允许任何种类的隐式类型转换。

  • 和省略号的匹配。省略号参数可以匹配任何类型(但匹配非PODplain old data)类型会导致未经定义的行为)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/128449.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java内存泄漏查找

    Java内存泄漏查找Java 由于拥有自动垃圾回收机制 所以一般情况下 我们不需要考虑内存泄漏的问题 jvm 会自动收回无用的对象 所谓无用的对象 表示你的程序不可能再访问的对象 但是 有一种情况必须考虑 就是要防止容器 List Map 等 内的对象无限增大 因为对象存贮在容器中 会被容器引用 从而如果容器的有效 容器内的对象就不会释放 一旦真的出现内存泄漏 随着时间的推移 java 程序逐渐增大内存消耗 最后出现

    2025年9月7日
    3
  • EnableEventValidation错误原因分析以及解决办法

    EnableEventValidation错误原因分析以及解决办法回发或回调参数无效。在配置中使用<pagesenableEventValidation="true"/>或在页面中使用<%@PageEnableEve

    2022年7月3日
    28
  • 图像的拼接—-RANSAC算法

    图像的拼接—-RANSAC算法一、全景拼接的原理1.RANSAC算法介绍RANSAC算法的基本假设是样本中包含正确数据(inliers,可以被模型描述的数据),也包含异常数据(outliers,偏离正常范围很远、无法适应数学模

    2022年7月2日
    24
  • 程序员该不该去外包公司_程序员项目外包

    程序员该不该去外包公司_程序员项目外包最近,关于“外包”的话题,在程序员之间讨论得十分热烈。究竟什么叫外包呢?在IT行业,有些程序员在大公司的办公楼里,跟正式员工们一起工作。但是,他们并不隶属于这家公司,而是属于第三方公司,比如博彦科技,比如文思海辉,比如中软国际……这些人就像是后妈的孩子,他们的薪酬远不如大公司的正式工,上升空间也有限。他们有个共同的名字,叫做外包人员。那么,年轻的程序员们该不该进入…

    2022年9月30日
    2
  • vue监听页面刷新事件_vue监听数据变化自动刷新

    vue监听页面刷新事件_vue监听数据变化自动刷新运用的知识点:JavaScript的onbeforeunload函数使用方法window.onbeforeunload=function(){  return‘’;}注意:有返回值(”,true,false…都可以)才能弹出显示,或者有需要执行的事件也行。onload、onunload、onbeforeunload的执行问题:页面加载…

    2025年8月3日
    5
  • 用斐波那契数列来说明递归和迭代的区别「建议收藏」

    用斐波那契数列来说明递归和迭代的区别「建议收藏」递归:自己调用自己迭代:反复替换的意思递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计数器,直到计数器值使循环条件失败;递归不断产生最初问题的简化副本

    2022年6月3日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号