iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >深入了解C++函数重载解析策略
  • 515
分享到

深入了解C++函数重载解析策略

C++函数重载解析C++函数重载 2022-11-13 18:11:08 515人浏览 安东尼
摘要

参考《c++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。C++ 使用重载解析策略来决定为函数调用使用哪一个函数定义。

参考《c++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。C++ 使用重载解析策略来决定为函数调用使用哪一个函数定义。重载解析过程大致分为如下三步:

第 1 步:创建候选函数列表,只要求函数名一样即可,对函数特征标以及是否为模板函数无要求;

第 2 步:在上一步的基础上创建可行函数列表,包含特征标完全匹配的常规函数或模板函数、以及实参隐式转换后完全匹配的常规函数或模板函数,这些都是参数数目正确的函数;

第 3 步:在上一步的基础上确定最佳匹配函数,若有则使用它,若没有则该函数调用失败。

下面以一个例子来说明这个重载过程:

//全部函数原型
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char * may(const char *);             //原型#4
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6
template<class T> void may(T *);      //原型#7
void may(char, double);               //原型#8
void mbk(float);                      //原型#9
char mkk(int, char);                  //原型#10
int mck(char);                        //原型#11
double myk(float);                    //原型#12
void mpk(char);                       //原型#13
 
//函数调用
may('B');
 
//函数定义
...

重载第 1 步:创建候选函数列表。即函数名称为 may 的常规函数和模板函数,候选函数列表如下:

//重载第1步:创建候选函数列表
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char * may(const char *);             //原型#4
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6
template<class T> void may(T *);      //原型#7
void may(char, double);               //原型#8

重载第 2 步:创建可行函数列表。由于整数类型 char 不能被隐式地转换为指针类型 char *,因此函数 #4 和函数 #7 都被排除,而函数 #8 因为参数数目不匹配也会被排除。进行完全匹配时,C++ 允许下表这些无关紧要的转换,表中 Type 表示任意类型,例如 char & 到 const char & 的转换也包含在内,表中 Type (argument-list) 意味着用作实参的函数名和用作形参的函数指针只要返回类型和参数列表相同,就是匹配的。

实参类型形参类型
TypeType &
Type &Type
Type []Type *
Type (argument-list)Type (*) (argument-list)
Typeconst Type
Typevolatile Type
Type *const Type *
Type *volatile Type *

根据此表可知,剩下的函数中包含特征标完全匹配的常规函数 #3 和 #5、特征标完全匹配的模板函数 #6(此时 T 可以被实例化为 char)、实参隐式转换后完全匹配的常规函数 #1 和 #2。可行函数列表如下:

//重载第2步:创建可行函数列表
void may(int);                        //原型#1
float may(float, float = 3);          //原型#2
void may(char);                       //原型#3
char may(const char &);               //原型#5
template<class T> void may(const T &);//原型#6

重载第 3 步:确定最佳匹配函数。通常,从最佳到最差的顺序如下所述:

  • 特征标完全匹配;
  • 类型需经隐式提升转换,例如 char 和 short 自动转换为 int,float 自动转换为 double;
  • 类型需经隐式标准转换,例如 int 转换为 char,long 转换为 double;
  • 类型需经隐式自定义转换,例如类中用户定义的类型转换。

依此规则,函数 #3 和函数 #5、函数 #6 都是特征标完全匹配的最佳匹配函数,函数 #1 需经隐式提升转换,函数 #2 需经隐式标准转换,由此各函数最佳匹配程度为:(#3, #5, #6) > #1 > #2。当特征标完全匹配时,又有如下规则:

  • 指向非 const 数据的指针和引用优先与形参为非 const 指针和引用的函数匹配;
  • 优先与非模板函数匹配;
  • 同为模板函数时,优先与较具体的模板函数匹配。

依此规则,非模板函数 #3 和 #5 最佳匹配程度要高于模板函数 #6 ,即各函数最佳匹配程度为:(#3, #5) > #6 > #1 > #2。最终出现了两个最佳匹配函数 #3 和 #5 ,因此该函数调用失败,编译器将报错。

//重载第 3 步:确定最佳匹配函数
void may(char);                       //原型#3
char may(const char &);               //原型#5

下面展开来说上述几条完全匹配时的规则。

第 1 条:指向非 const 数据的指针和引用优先与形参为非 const 指针和引用的函数匹配,这一点需明确,const 和非 const 之间的区别只适用于指针和引用。下面 4 个函数都与函数调用是完全匹配的:

//函数原型
void recycle(int);        //原型#1
void recycle(const int);  //原型#2
void recycle(int &);      //原型#3
void recycle(const int &);//原型#4
 
//函数调用
int x = 5;
recycle(x);
 
//函数定义
...
  • 如果这 4 个函数同时存在,则无法完成重载,编译器会报多义性匹配的错误;
  • 如果只存在函数 #1 与 #2,则无法完成重载,编译器会报重复定义的错误;
  • 如果只存在函数 #1 与 #3,则无法完成重载,编译器会报多义性匹配的错误;
  • 如果只存在函数 #1 与 #4,则无法完成重载,编译器会报多义性匹配的错误;
  • 如果只存在函数 #2 与 #3,则无法完成重载,编译器会报多义性匹配的错误;
  • 如果只存在函数 #2 与 #4,则无法完成重载,编译器会报多义性匹配的错误;
  • 如果只存在函数 #3 与 #4,则函数调用时编译器将会选择 #3。

第 2 条:优先与非模板函数匹配,这一点比较简单,当完全匹配的函数中,一个是非模板函数,另一个是模板函数时,非模板函数将优于模板函数,显式具体化、显式实例化、隐式实例化都属于模板函数。

第 3 条:同为模板函数时,优先与较具体的模板函数匹配,找出最具体的模板的规则被称为函数模板的部分排序规则(partial ordering rules)。这意味着显式具体化优先于常规模板函数,都为常规模板函数时,编译器优先选择实例化时类型转换更少的那一个。以下面的程序为例,调用方式 recycle(&ink) 既与模板 #1 匹配,此时 Type 将被解释为 blot *,也与模板 #2 匹配,此时 Type 将被解释为 blot,因此将这两个隐式实例 recycle<blot *>(blot *) 和 recycle<blot>(blot *) 发送到可行函数池中。在选择最佳匹配函数时,#2 被认为是更具体的,因为它已经显式地指出,函数参数是指向 Type 的指针,相比于 #1,它对类型的要求更加地具体,在生成过程中所需要的转换更少,因此调用方式 recycle(&ink) 实际会匹配版本 #2。

//两个常规模板函数
template <class Type> void recycle(Type t);   //原型#1
template <class Type> void recycle(Type * t); //原型#2
 
//调用程序包含如下代码
struct blot {int a; char b[10];};
blot ink = {25, "spots"};
...
recycle(&ink);  //使用版本#2
 
//函数定义
...

部分排序规则的另一个示例程序如下,它与上一个例子有异曲同工之妙。由于模板 #2 做了特定的假设:数组内容是指针,对类型的要求更加地具体,因此在调用时第一个参数若传入指针数组 pt,则将实际匹配函数 #2。

//两个常规模板函数
template <typename T> 
void ShowArray(T arr[], int n);   //原型#1
template <typename T> 
void ShowArray(T * arr[], int n); //原型#2
 
//调用程序包含如下代码
int things[6] = {13, 31, 103, 301, 310, 130};
int * pt[3] = {&things[0], &things[2], &things[4]};
ShowArray(things, 6);  //使用版本#1
ShowArray(pt, 3);      //使用版本#2
 
//函数定义
...

将有多个参数的函数调用与有多个参数的原型进行匹配时,编译器必须考虑所有参数的匹配情况。如果找到比其他可行函数都合适的函数,则选择该函数。一个函数要比其他函数都合适,其所有参数的匹配程度都必须不比其他函数差,同时至少有一个参数的匹配程度比其他函数都高。

在有些情况下,可通过编写合适的函数调用,来引导编译器做出程序员期望的选择。如下所示,其中模板函数返回两个值中较小的一个,非模板函数返回两个值中绝对值较小的那个。第一次调用时根据重载解析策略选择了非模板函数 #2;第二次调用时根据重载解析策略选择了模板函数 #1 的 double 版本,属于模板函数的隐式实例化;第三次调用的 <> 指出,编译器应该选择模板函数,此时编译器会查看调用函数时的实参类型来进行实例化,也属于模板函数的隐式实例化;第四次调用的 <int> 显式指出,编译器应该使用模板函数的 int 实例化版本,此时属于模板函数的显式实例化。

#include <iOStream>
 
//函数#1
template<class T>
T lesser(T a, T b)
{
    return a < b ? a : b;
}
 
//函数#2
int lesser(int a, int b)
{
    a = a < 0 ? -a : a;
    b = b < 0 ? -b : b;
    return a < b ? a : b;
}
 
//函数调用
int main()
{
    using namespace std;
    
    int m = 20;
    int n = -30;
    double x = 15.5;
    double y = 25.9;
    
    //使用#2,结果为20
    cout << lesser(m, n) << endl;
    
    //使用#1,double隐式实例化,结果为15.5
    cout << lesser(x, y) << endl;
    
    //使用#1,int隐式实例化,结果为-30
    cout << lesser<>(m, n) << endl;
    
    //使用#1,int显式实例化,结果为15
    cout << lesser<int>(x, y) << endl;
    
    return 0;
}

到此这篇关于深入了解C++函数重载解析策略的文章就介绍到这了,更多相关C++函数重载解析内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 深入了解C++函数重载解析策略

本文链接: https://www.lsjlt.com/news/169731.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 深入了解C++函数重载解析策略
    参考《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,张海龙 袁国忠译,人民邮电出版社。C++ 使用重载解析策略来决定为函数调用使用哪一个函数定义。...
    99+
    2022-11-13
    C++函数重载解析 C++函数重载
  • C++深入讲解函数重载
    目录函数重载概念重载依据值型别判断函数重载的规则名字粉碎-名字修饰函数重载 概念 在C++中可以为两个或者两个以上函数提供相同的函数名称,只要参数类型不同,或者参数数目不同,参数顺序...
    99+
    2024-04-02
  • C++深入浅出讲解函数重载
    目录前言函数重载1.1 函数重载的概念1.2 函数重载的意义1.3 名字修饰(name Mangling)1.4 extern "C"前言 自然语言中,一个词可以...
    99+
    2024-04-02
  • C++深入分析讲解函数与重载知识点
    目录函数的默认(缺省)参数1、默认参数的定义2、默认参数的注意点占位参数1、占位参数 函数内部无法使用2、占位参数 可以设置成缺省参数函数重载函数的默认(缺省)参数 1、默认参数的定...
    99+
    2024-04-02
  • C++深入分析回顾函数重载
    目录一、函数重载回顾二、类中的重载三、重载的意义四、小结一、函数重载回顾 函数重载的本质为相互独立的不同函数C++ 中通过函数名和函数参数确定函数调用无法直接通过函数名得到重载函数的...
    99+
    2024-04-02
  • C语言深入了解函数
    目录1. 函数的概念2. 函数的分类从定义角度分从参数角度分类从返回值角度分3. 函数的定义4. 函数的声明5. 函数的调用6. 递归函数1. 函数的概念 函数是c语言的功能单位,实...
    99+
    2024-04-02
  • 深入解析MongoDB的数据备份与恢复策略
    深入解析MongoDB的数据备份与恢复策略摘要:MongoDB是一款非常流行的NoSQL数据库,为了确保数据的安全性和可靠性,在使用MongoDB时,合理的备份与恢复策略是至关重要的。本文将对MongoDB数据备份与恢复的相关内容进行深入解...
    99+
    2023-11-03
    MongoDB 数据备份 恢复策略
  • C++ 函数的重载用法解析
    函数重载允许使用相同名称创建具有不同参数列表的函数,从而实现代码灵活性。规则包括:函数名称相同,参数列表不同,可不同类型或数量。例如,计算面积的类包含针对不同形状的重载函数,可根据形状类...
    99+
    2024-04-18
    c++ 函数重载
  • 深入了解Java设计模式之策略模式
    目录定义解决的问题核心要点类图溢出效用代码实现核心接口实现类-三个Context类Main方法拓展JDK源码Spring源码定义 定义了算法家族,分别封装起来,让他们之间可以相互替换...
    99+
    2024-04-02
  • 深入了解java内存分配和回收策略
    一、导论java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配。通俗的讲,对象的内存分配就是在堆上的分配,对象主要分配在新生代的E...
    99+
    2023-05-31
    java 内存分配 回收策略
  • 深入了解C++的多态与虚函数
    目录1.多态的机制与虚函数的机制1.1 多态的机制1.2 虚函数的机制1.3虚函数表的结构图1.4 动态多态实现的三个前提件(很重要)2.多态实例应用3.多态的巨大问题与虚析构3.1...
    99+
    2024-04-02
  • 深入了解Java方法的重载与重写
    目录1.方法的重载1.1.基本介绍1.2.重载的好处1.3.重载使用细节1.4.可变参数2.方法的重写2.1.基本介绍2.2.重写的好处2.3.重写的细节3.重写与重写的对比1.方法...
    99+
    2024-04-02
  • 深入了解阿里云服务器的价格策略
    本文将深入探讨阿里云服务器的价格策略,包括定价模型、优惠政策以及选择最佳方案的方法。 一、阿里云服务器的价格策略阿里云服务器的定价策略主要包括按需付费和包年包月两种方式。按需付费模式下,用户可以根据自己的需求购买所需的计算资源,根据实际使用...
    99+
    2024-01-26
    阿里 策略 服务器
  • C++入门语法之函数重载详解
    目录写在前面1 函数重载的概念2 函数重载原理总结写在前面 关于C语言的编译与链接不懂的可以看一下下面的文章,先回顾一下以前的知识。 详解C语言的编译与链接 1 函数重载的概念 函数...
    99+
    2024-04-02
  • 深入解析MySQL索引的原理与优化策略
    目录索引的概念索引的原理索引的类型索引的使用索引的使用方式注意事项索引优化技巧索引的概念 mysql索引是一种用于加速数据库查询的数据结构,它类似于书籍的目录,能够快速指导我们找到需要的信息。MySQL索引可以根据一定的...
    99+
    2023-03-31
    解析MySQL索引原理和优化策略 MySQL索引原理 MySQL优化策略
  • C++ 函数重载的解析和优先级
    函数重载允许创建具有相同名称但参数列表不同的多个函数。解析:将多个同名函数定义到同一名称空间中,每个重载必须具有独特的参数列表。优先级:选择要调用的函数时,编译器按照以下优先级进行匹配:...
    99+
    2024-04-13
    c++ 函数重载
  • JavaScript前端优化策略深入详解
    目录虚拟滚动虚拟滚动插件Web Worker优化长任务Web Worker的通信时长requestAnimationFrame 制作动画JS的加载方式加载方式的总结虚拟滚动 当我们开...
    99+
    2023-05-19
    JS前端优化策略 JS优化策略
  • C++中函数重载详解
    目录函数重载的概念函数重载的应用 为什么C++支持函数重载,而C语言不支持函数重载的概念 函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函...
    99+
    2024-04-02
  • 深入了解PHP错误级别分类及应对策略
    PHP是一种广泛应用于网站开发的服务器端脚本语言,它的灵活性和易用性使其成为许多网站开发者的首选。然而,在使用PHP开发过程中,不可避免会遇到各种错误。对于PHP错误的处理,了解错误级...
    99+
    2024-03-08
    应对策略 深入了解 php错误级别
  • 深入了解python的函数参数
    目录位置参数默认参数关键字参数多值参数:总结 位置参数 这是一个求等差数列和的函数,使用必需要传入一个参数n,这就是位置参数 def sum(n): sum=0 ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作