当前位置: 首页 > news >正文

C++入门:函数重载

目录

一. 函数重载的概念和分类

1.1 什么是函数重载

1.2 函数重载的分类

1.3 关于函数重载的几点注意事项

二. C++实现函数重载的底层逻辑(为什么C++可以实现函数重载而C语言不能)

2.1 编译器编译程序的过程

2.2 为什么C++可以实现函数重载而C语言不能

2.3 Linux环境下C++编译器对函数名的修饰规则


一. 函数重载的概念和分类

1.1 什么是函数重载

函数重载是函数的一种特殊情况,C++允许在同一作用域中定义或声明几个名称相同的函数,这些同名函数经常用于处理形参不同(形参个数、类型或顺序不同),但是实现功能类似的函数。如:int Add(int a, int b)和int Add(double a, double)就可以构成一组函数重载。

注意:C语言不支持函数重载。

1.2 函数重载的分类

函数重载有3种情况:参数类型不同、参数个数不同、参数顺序不同。满足上述3种情况至少其中一种,才能构成函数重载。

参数类型不同

两个重名函数,如果参数类型不同,可以构成函数重载。演示代码1.1定义了两个求加法函数Add,一个是针对整形数据的int Add(int x, int y),另一个是针对双精度浮点型数据的double Add(double x, double y)。在调用Add函数时,如果传入两个整形数据,就调用nt Add(int x, int y),如果传入两个双精度浮点型数据,就调用Add(double x, double y)。

编译器会自动识别调用两个重名函数中的哪一个,无需任何额外语句。

演示代码1.1:

#include<iostream>
using namespace std;//对整形数据的加法函数
int Add(int x, int y)
{cout << "int Add(int x, int y)" << endl;return x + y;
}//对浮点型数据的Add函数
double Add(double x, double y)
{cout << "double Add(double x, double y)" << endl;return x + y;
}int main()
{int add_int = Add(2, 5);  //整形数据加法printf("add_int = %d\n", add_int);  //7double add_double = Add(2.1, 3.5);  //浮点型数据加法printf("add_double = %lf\n", add_double);  //5.6return 0;
}
图1.1 演示代码1.1的运行结果

参数个数不同

演示代码1.2定义了两个Add函数,分别实现对两个数据求加法和对三个数据求加法。通过控制调用函数时传给函数的参数个数,来确定调用哪个Add函数。

演示代码1.2:

#include<iostream>
using namespace std;//对2个整形数据的加法函数
int Add(int x, int y)
{cout << "int Add(int x, int y)" << endl;return x + y;
}//对3个整形数据的加法函数
int Add(int x, int y, int z)
{cout << "int Add(int x, int y, int z)" << endl;return x + y + z;
}int main()
{int add_two = Add(1, 2);printf("add_two = %d\n", add_two);  //3int add_three = Add(1, 2, 3);printf("add_three = %d\n", add_three);  //6return 0;
}
图1.2  演示代码1.2的运行结果

形参顺序不同

演示代码1.3定义了两个func函数,第一个func函数的两个形参char类型数据在前、int类型数据在后,第二个func函数int类型数据在前、char类型数据在前。在调用函数时,通过控制传给函数的参数类型的顺序,来确定调用哪个func函数。

演示代码1.3:

#include<iostream>
using namespace std;void func(char c, int i)
{cout << "void func(char c, int i)" << endl;
}void func(int i, char c)
{cout << "void func(int i, char c)" << endl;
}int main()
{func('A', 5);func(5, 'A');return 0;
}
图1.3  演示代码1.3的运行结果

1.3 关于函数重载的几点注意事项

返回值不同,不能构成重载

double func(int a)和int func(int a)不构成重载,因为其不满足函数的参数类型、个数或顺序不同中的任意一个,因此不能构成重载。

缺省值不同,不能构成重载

func(int a)和func(int a = 10)不能构成重载,这里的原因与返回值不同时的类似, 不满足函数的参数类型、个数或顺序不同中的任意一个。

总结:判断两个重名函数是否能构成重载,只需看函数参数的个数、类型和顺序是否满足条件,不用关注缺省值、返回值等任何其余问题。

func()和func(int a = 10)可以构成重载

虽然这两个同名函数可以构成重载,但在调用时,会出现歧义。如果通过语句func()调用函数,编译器无法确定这里应当处理为没有传入参数调用func()还是存在缺省参数调用func(10)。 

二. C++实现函数重载的底层逻辑(为什么C++可以实现函数重载而C语言不能)

2.1 编译器编译程序的过程

要弄清楚C++实现函数重载的底层逻辑,首先要清楚编译器编译程序的全过程。将一份程序文献生成可执行文件,要经历编译和链接两段过程,其中编译又可以细分为预编译、编译和汇编三个小过程。汇编过程结束时,每个.c(.cpp)文件都会生成一份目标文件(后缀名为.obj或.o),完成链接过程后,就会生成可执行程序。

图2.1 编译器编译程序的过程

预编译阶段

预编译阶段完成的工作包括:

  • 注释的删除
  • #define定义符号和宏的替换
  • 头文件的包含
  • 条件编译

编译阶段

编译阶段将C++代码或C语言代码转换为汇编代码,完成的工作有:

  • 语法检查
  • 符号汇总(只汇总全局符号,不汇总局部作用域中定义的临时变量名或函数名等)

汇编阶段

将汇编语言转换为计算机能够读懂的机器语言(二进制代码),这个过程完成的具体工作有:

  • 符号表的生成(每个.c/.cpp文件都会生成一份符号表)

符号表中存有符号的名称和其存储在内存中的地址,如果在当前.c\.cpp文件中仅声明了某个符号而没有定义,这样对这个.c/.cpp文件编译时就无法在内存中找到这个符号,这是,符号表中就会存储一份虚拟地址。

链接阶段

链接阶段完成的具体工作有:

  • 合并段表
  • 符号表的合并和重定位

如果在.c文件中调用一个没有被定义的函数或多次被定义的函数,编译器会在链接阶段检测出函数未定义或重复定义。理解链接阶段也是理解为什么C++能够支持函数重载而C语言不能支持函数重载的关键。

2.2 为什么C++可以实现函数重载而C语言不能

假设在主函数中调用Add函数,该函数的函数原型为int Add(int x, int y),而该函数仅被声明而没有被定义。在Windows环境先使用VS2019编译器,分别在C语言和C++编译环境下对程序进行编译,可以观察的报错信息:

  • 在C语言编译环境下,报错信息为:无法解析外部符号_Add
  • C++编译环境下,报错信息为:无法解析外部符号int _cdcel Add(int, int)(?Add@@YAHH@z)
图2.2  C语言报错信息
图2.3  C++报错信息

根据报错信息的不同,可以初步推断,C++编译器在汇总函数名符号时,会对函数名进行修饰。根据初步的推断,我们在VS2019编译器中,定义并调用Add函数(Add函数的定义和调用不再同一个.cpp文件中)。对演示代码2.1进行调试(其中的Add函数已有定义),观察其汇编代码(如图2.4所示),汇编指令 call 表示调用函数,图中Add后面括号里的内容为函数地址。

call指令通俗来讲就是实现“跳转过程”,程序在执行main函数中的命令时,在某一位置跳转去执行被调函数地址处的命令。

对于Add后面括号里的地址在什么阶段填入问题,分以下两种情况讨论:

  • 如果调用Add的.cpp文件中定义了Add函数,那么在编译阶段生成符号表时就会填入函数地址。
  • 如果Add函数定义在了其他.cpp文件而调用Add函数的.cpp文件中仅有函数的声明,那么就需要在链接阶段才会填入函数地址。
图2.4  函数调用的汇报代码

 如果此时发现了两个互相冲突的函数,则无法确定应该执行存储在哪一地址处的函数指令。

  • 对于C语言编译器,在生成符号表时,使用的函数名是原本程序中程序员定义的函数名,根据函数名标识查找函数所在的地址,此时如果存在两个相同的函数,函数名就会发生冲突。
  • 对于C++编译器,生成符号表时使用的函数名是经过一定的修饰规则修饰后的函数名,在函数调用时也是采用经修饰后的函数名标识查找函数所在的地址,只要函数的参数不同,调用两个名称相同的函数就不会存在歧义。

2.3 Linux环境下C++编译器对函数名的修饰规则

Linux环境下C++对函数名的修饰规则为:_Z + 函数名长度 + 函数名 + 参数信息

如:int func()在Linxu环境下被修饰后,函数名变为:_Z4funcv。其中:

  • _Z:表示前缀
  • 4:表示函数名有4个字符
  • func:程序员定义的函数名func
  • v:表示函数没有参数

再比如:int func(int x, int y),经修饰后的函数名变为:_Z4funcii,其中ii表示函数有两个整形参数。对更复杂一些的情况,如int func(int i, int* pi),经修饰后函数名变为:Z4funciPi,其中Pi表示int*类型的参数。

在Window环境下,函数名的修饰规则更为复杂。但是,我们只需要知道C++会按照一定的规则对函数原本的名称进行修饰,通过修饰后的函数名查找函数地址即可,没必要深究修饰规则。

 

相关文章:

C++入门:函数重载

目录 一. 函数重载的概念和分类 1.1 什么是函数重载 1.2 函数重载的分类 1.3 关于函数重载的几点注意事项 二. C实现函数重载的底层逻辑&#xff08;为什么C可以实现函数重载而C语言不能&#xff09; 2.1 编译器编译程序的过程 2.2 为什么C可以实现函数重载而C语言不能 …...

每天10个前端小知识 【Day 16】

&#x1f469; 个人主页&#xff1a;不爱吃糖的程序媛 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域新星创作者、CSDN内容合伙人&#xff0c;专注于前端各领域技术&#xff0c;成长的路上共同学习共同进步&#xff0c;一起加油呀&#xff01; ✨系列专栏&#xff1a;前端…...

23美赛D题:确定联合国可持续发展目标的优先级(ICM)思路Python代码

问题D(交叉网络建模题):确定联合国可持续发展目标的优先级(ICM) 赛题目的:对联合国制定的17个可持续发展目标进行关系网络的构建同时评估其可能存在的影响赛题解读&解题思路链接:交叉网络回归路径分析,如何寻找到能代表可持续发展目标的数值是这道题的难点。背景 联…...

高校房产管理系统有哪些管理功能范围?

数图互通高校房产管理系统是基于公司自主研发的FMCenterV5.0平台&#xff0c;是针对中国高校房产的管理特点和管理要求&#xff0c;研发的一套标准产品&#xff1b;通过在中国100多所高校的成功实施和迭代&#xff0c;形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。…...

ACM MM 相关内容的整理+汇总

目录一、网址二、重要时间点三、论文篇幅要求四、征稿主题五、论文格式相关要求六、论文模板修改成投稿模式上述参考七、模板使用相关八、关于图片方面的问题九、Review and Rebuttal十、ACM MM2022相关论文参考arxiv上 ACM MM2022 论文汇总一、网址 ACM MM2023 主页&#xff1…...

前段时间公司招人,面了一个要20K的,一问自动化只会点皮毛···

前段时间公司要招2个自动化测试&#xff0c;同事面了几十个候选人&#xff0c;发现了一个很奇怪的现象&#xff0c;面试的时候&#xff0c;如果问的是框架api、脚本编写这些问题&#xff0c;基本上个个都能对答如流&#xff0c;等问到实际项目的时候&#xff0c;类似“怎么从0开…...

链表:反转链表、快慢指针、删除链表【零神基础精讲】

来源0x3f&#xff1a;https://space.bilibili.com/206214 文章目录反转链表[206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)[92. 反转链表 II](https://leetcode.cn/problems/reverse-linked-list-ii/)[25. K 个一组翻转链表](https://leetcode.cn/proble…...

SQlServer 定时执行sql语句作业的制定

1、打开【SQL Server Management Studio】&#xff0c;在【对象资源管理器】列表中选择【SQL Server 代理】&#xff1b; 2、鼠标右击【SQL Server 代理】&#xff0c;选择【启动(S)】&#xff0c;如已启动&#xff0c;可以省略此步骤&#xff1b; 3、展开【SQL Server 代理】列…...

Windows安装VMware虚拟机+配置Ubuntu的详细步骤以及解决配置过程中报错的问题(完整版)

目录 引言: 过程&#xff1a; 安装VMware虚拟机&#xff1a; 在VMware虚拟机中配置Ubuntu&#xff1a; 在VMware虚拟机中安装Ubuntu&#xff1a; VMware中启动虚拟机时报错问题的解决&#xff1a; 正式开始安装Ubuntu&#xff1a; 参考资料&#xff1a; 引言: 在学习计…...

103.第十九章 MySQL数据库 -- MySQL的备份和恢复、MySQL主从复制(十三)

mysqldump 常见通用选项: -A, --all-databases #备份所有数据库,含create database -B, --databases db_name… #指定备份的数据库,包括create database语句 -E, --events:#备份相关的所有event scheduler -R, --routines:#备份所有存储过程和自定义函数 --triggers:#备…...

SSH免密登录以及IP别名配置(保姆级教程)

目录 设置免密登录 客户端生成密钥 将公钥上传到服务器 创建别名 创建config配置 配置说明 保持SSH连接不断 方案一 方案二 设置免密登录 客户端生成密钥 在终端输入如下命令&#xff0c;进行回车即可完成后会在用户目录下的.ssh目录下生成公钥id_rsa.pub和私钥id_r…...

测试开发之Django实战示例 第十二章 创建API

第十二章 创建API在上一章里&#xff0c;创建了一个学生注册系统和选课系统。然后创建了展示课程内容的视图&#xff0c;以及学习了如何使用Django缓存框架。在这一章里有如下内容&#xff1a;建立RESTful API管理API视图的认证与权限建立API视图集和路由1创建RESTful API你可能…...

Yakit实战技巧:用MITM热加载任意修改流量

背景 用户在使用 Yakit MITM 功能的时候&#xff0c;经常会遇到一些特殊需求&#xff1a; 我的数据包需要携带一些特征变量才能访问&#xff0c;但是浏览器无法做到&#xff0c;我可以批量修改流量新增某一个 Header 吗&#xff1f; 我可以在代理层面在所有流量中新增一个参数…...

如何搭建自己的MQTT服务器?跟我来,一行代码搞定!

如何搭建自己的MQTT服务器&#xff1f;跟我来&#xff0c;一行代码搞定&#xff01;什么是mosquitto&#xff1f;如何使用mosquitto云服务器注意事项MQTT客户端软件下载在文章开始之前&#xff0c;你首先需要有一台服务器&#xff0c;我这里用的是阿里云的轻量级云服务器&#…...

遇到的问题

一、axios 请求 1、axios post 提交的请求的 content-type 为 json 默认情况下&#xff0c;axios将JavaScript对象序列化为JSON&#xff0c;再发送数据application/x-www-form-urlencoded格式相反&#xff0c;您可以使用URLSearchParamsAPI&#xff0c;也就是支持在绝大多数…...

线程没有被终止的异常的处理

process Runtime.getRuntime().exec(command); process.waitFor(); // 这个调用比较关键&#xff0c;就是等当前命令执行完成后再往下执行 if (!file.exists()) { Ulog.error("html转pdf执行失败"); } else { …...

RocketMQ 初步了解

RocketMQ 初步了解 前言&#xff1a; ​  近期&#xff0c;因公司使用 RocketMQ 作为消息队列中间件&#xff0c;特此了解。  RocketMQ 是阿里巴巴在 2012 年开发的分布式消息中间件&#xff0c;专为万亿级超大规模的消息处理而设计&#xff0c;具有高吞吐量、低延迟、海量…...

Mac下PyCharm快捷键

Mac键盘符号和修饰键说明 ⌘ Command⇧ Shift⌥ Option⌃ Control↩︎ Return/Enter⌫ Delete⌦ 向前删除键&#xff08;FnDelete&#xff09;↑ 上箭头↓ 下箭头← 左箭头→ 右箭头⇞ Page Up&#xff08;Fn↑&#xff09;⇟ Page Down&#xff08;Fn↓&#xff09;Home Fn …...

城市管网监测系统,保障城市血管生命线!

各种不同的管网线路组成了城市的供血管道&#xff0c;管网对于维持正常的社会生活、生产秩序和公共安全至关重要。我国城市平均漏损率达到38%&#xff0c;部分城市甚至超过50%&#xff0c;远超发达国家的平均水平&#xff08;10%&#xff09;。对于管道状态的监测&#xff0c;是…...

Web3中文|1月数据显示复苏迹象,涉及NFT、DeFi、Dapp、链游……

本期看点 1、Dapp行业概述 2、DeFi的TVL增长26.8%&#xff0c;有回暖迹象 3、NFT市场数据飙升&#xff0c;交易额达9.46亿美元 4、链游使用量占行业48% 5、与去年相比&#xff0c;1月份区块链漏洞损失最低 区块链领域正在多元化发展&#xff0c;2023年1月&#xff0c;从各…...

从机器学习转做DFT计算?手把手教你用Python ASE库搞定VASP输入文件(含VC++14安装避坑)

从机器学习转做DFT计算&#xff1f;用Python ASE库高效构建VASP输入文件全指南 当机器学习背景的研究者首次接触第一性原理计算时&#xff0c;往往会被VASP等传统软件的复杂输入文件格式所困扰。POSCAR、INCAR、KPOINTS这些文件的手动编写不仅耗时&#xff0c;还容易出错。本文…...

Android本地AI语音助手Cliff:开源、离线与可定制的边缘计算实践

1. 项目概述&#xff1a;Cliff&#xff0c;一个运行在Android上的本地化AI语音助手最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“Cliff-Android-Voice-Assistant”。光看名字&#xff0c;你大概能猜到它是一个给安卓设备用的语音助手。但和Siri、小爱同学、Google Ass…...

计算机视觉工程师必须掌握的颜色空间选型指南

1. 项目概述&#xff1a;为什么计算机视觉工程师必须懂颜色理论你有没有遇到过这样的情况&#xff1a;模型在训练集上准确率98%&#xff0c;一到测试集就掉到72%&#xff1f;调试半天发现&#xff0c;不是数据标注错了&#xff0c;也不是网络结构有问题&#xff0c;而是训练图像…...

虚拟工业仿真软件能模拟实操吗?看完你就懂了

在高端制造与复杂工程场景中&#xff0c;工业仿真软件是否只是“纸上谈兵”&#xff1f;它能否真正模拟出真实的物理过程、操作流程与系统行为&#xff1f;答案是&#xff1a;可以&#xff0c;而且正在改变工业研发的逻辑。秩益科技自主研发的DIMAXER工业仿真软件&#xff0c;正…...

Andorid下给PDF盖骑缝章的方法—安卓手机批量盖骑缝章的方法

Andorid下给PDF盖骑缝章的方法&#xff0c;安卓手机批量盖骑缝章的方法。一、准备印章图片1。不需要制作为透明的印章&#xff0c;用白底Png格式图片即可&#xff0c;白底图片盖章时软件会自动透明并融合。2。印章边线与图片四边不要有空隙&#xff0c;如下&#xff1a;错误的&…...

OpenAccess十年:EDA互操作性标准如何重塑芯片设计流程

1. 从愿景到现实&#xff1a;OpenAccess十年之路的深度复盘十年前&#xff0c;也就是2002年的12月&#xff0c;当Si2&#xff08;硅集成倡议组织&#xff09;首次向联盟成员发布OpenAccess 2.0时&#xff0c;恐怕没有多少人能预料到&#xff0c;这个源于半导体巨头内部需求的“…...

Argo CD 集成 Helmfile 插件:实现 GitOps 下复杂应用声明式部署

1. 项目概述与核心价值如果你正在使用 Argo CD 管理 Kubernetes 集群&#xff0c;并且你的应用清单是由 Helmfile 来编排的&#xff0c;那么travisghansen/argo-cd-helmfile这个项目很可能就是你一直在寻找的“粘合剂”。简单来说&#xff0c;它是一个专门为 Argo CD 设计的 He…...

微信视频下载器wx_channels_download

微信视频下载器ltaoo/wx_channels_download&#xff08;跨平台轻量首选&#xff09; 特点&#xff1a;体积小、使用简单&#xff0c;在微信PC端视频下方添加“下载”按钮&#xff1b;支持 macOS 和 Windows。优点&#xff1a;集成式&#xff08;无需单独监听&#xff09;&…...

【研报 A110】物理AI时代的具身数据采集需求研究:国家级训练场落地,开源生态加速建设

摘要&#xff1a;物理AI时代&#xff0c;具身智能与世界模型的发展&#xff0c;推动具身数据采集成为下一代数据基建的核心浪潮。具身大模型对数据有着EB级的海量需求&#xff0c;同时对多模态、异构性与质量要求极高&#xff0c;当前数据缺口成为制约具身智能发展的核心瓶颈&a…...

手把手教你用Simulink搭建BUCK电路:从主电路到PID整定的保姆级流程

手把手教你用Simulink搭建BUCK电路&#xff1a;从主电路到PID整定的保姆级流程 电力电子技术作为现代能源转换的核心&#xff0c;BUCK电路因其高效的降压特性被广泛应用于电源设计领域。对于初学者而言&#xff0c;理论知识与实际仿真之间往往存在一道难以跨越的鸿沟——明明理…...