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.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.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 关于函数重载的几点注意事项
返回值不同,不能构成重载
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),完成链接过程后,就会生成可执行程序。
预编译阶段
预编译阶段完成的工作包括:
- 注释的删除
- #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)
根据报错信息的不同,可以初步推断,C++编译器在汇总函数名符号时,会对函数名进行修饰。根据初步的推断,我们在VS2019编译器中,定义并调用Add函数(Add函数的定义和调用不再同一个.cpp文件中)。对演示代码2.1进行调试(其中的Add函数已有定义),观察其汇编代码(如图2.4所示),汇编指令 call 表示调用函数,图中Add后面括号里的内容为函数地址。
call指令通俗来讲就是实现“跳转过程”,程序在执行main函数中的命令时,在某一位置跳转去执行被调函数地址处的命令。
对于Add后面括号里的地址在什么阶段填入问题,分以下两种情况讨论:
- 如果调用Add的.cpp文件中定义了Add函数,那么在编译阶段生成符号表时就会填入函数地址。
- 如果Add函数定义在了其他.cpp文件而调用Add函数的.cpp文件中仅有函数的声明,那么就需要在链接阶段才会填入函数地址。
如果此时发现了两个互相冲突的函数,则无法确定应该执行存储在哪一地址处的函数指令。
- 对于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实现函数重载的底层逻辑(为什么C可以实现函数重载而C语言不能) 2.1 编译器编译程序的过程 2.2 为什么C可以实现函数重载而C语言不能 …...
每天10个前端小知识 【Day 16】
👩 个人主页:不爱吃糖的程序媛 🙋♂️ 作者简介:前端领域新星创作者、CSDN内容合伙人,专注于前端各领域技术,成长的路上共同学习共同进步,一起加油呀! ✨系列专栏:前端…...
23美赛D题:确定联合国可持续发展目标的优先级(ICM)思路Python代码
问题D(交叉网络建模题):确定联合国可持续发展目标的优先级(ICM) 赛题目的:对联合国制定的17个可持续发展目标进行关系网络的构建同时评估其可能存在的影响赛题解读&解题思路链接:交叉网络回归路径分析,如何寻找到能代表可持续发展目标的数值是这道题的难点。背景 联…...
高校房产管理系统有哪些管理功能范围?
数图互通高校房产管理系统是基于公司自主研发的FMCenterV5.0平台,是针对中国高校房产的管理特点和管理要求,研发的一套标准产品;通过在中国100多所高校的成功实施和迭代,形成了一套成熟、完善、全生命周期的房屋资源管理解决方案。…...
ACM MM 相关内容的整理+汇总
目录一、网址二、重要时间点三、论文篇幅要求四、征稿主题五、论文格式相关要求六、论文模板修改成投稿模式上述参考七、模板使用相关八、关于图片方面的问题九、Review and Rebuttal十、ACM MM2022相关论文参考arxiv上 ACM MM2022 论文汇总一、网址 ACM MM2023 主页࿱…...
前段时间公司招人,面了一个要20K的,一问自动化只会点皮毛···
前段时间公司要招2个自动化测试,同事面了几十个候选人,发现了一个很奇怪的现象,面试的时候,如果问的是框架api、脚本编写这些问题,基本上个个都能对答如流,等问到实际项目的时候,类似“怎么从0开…...
链表:反转链表、快慢指针、删除链表【零神基础精讲】
来源0x3f: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】,在【对象资源管理器】列表中选择【SQL Server 代理】; 2、鼠标右击【SQL Server 代理】,选择【启动(S)】,如已启动,可以省略此步骤; 3、展开【SQL Server 代理】列…...
Windows安装VMware虚拟机+配置Ubuntu的详细步骤以及解决配置过程中报错的问题(完整版)
目录 引言: 过程: 安装VMware虚拟机: 在VMware虚拟机中配置Ubuntu: 在VMware虚拟机中安装Ubuntu: VMware中启动虚拟机时报错问题的解决: 正式开始安装Ubuntu: 参考资料: 引言: 在学习计…...
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连接不断 方案一 方案二 设置免密登录 客户端生成密钥 在终端输入如下命令,进行回车即可完成后会在用户目录下的.ssh目录下生成公钥id_rsa.pub和私钥id_r…...
测试开发之Django实战示例 第十二章 创建API
第十二章 创建API在上一章里,创建了一个学生注册系统和选课系统。然后创建了展示课程内容的视图,以及学习了如何使用Django缓存框架。在这一章里有如下内容:建立RESTful API管理API视图的认证与权限建立API视图集和路由1创建RESTful API你可能…...
Yakit实战技巧:用MITM热加载任意修改流量
背景 用户在使用 Yakit MITM 功能的时候,经常会遇到一些特殊需求: 我的数据包需要携带一些特征变量才能访问,但是浏览器无法做到,我可以批量修改流量新增某一个 Header 吗? 我可以在代理层面在所有流量中新增一个参数…...
如何搭建自己的MQTT服务器?跟我来,一行代码搞定!
如何搭建自己的MQTT服务器?跟我来,一行代码搞定!什么是mosquitto?如何使用mosquitto云服务器注意事项MQTT客户端软件下载在文章开始之前,你首先需要有一台服务器,我这里用的是阿里云的轻量级云服务器&#…...
遇到的问题
一、axios 请求 1、axios post 提交的请求的 content-type 为 json 默认情况下,axios将JavaScript对象序列化为JSON,再发送数据application/x-www-form-urlencoded格式相反,您可以使用URLSearchParamsAPI,也就是支持在绝大多数…...
线程没有被终止的异常的处理
process Runtime.getRuntime().exec(command); process.waitFor(); // 这个调用比较关键,就是等当前命令执行完成后再往下执行 if (!file.exists()) { Ulog.error("html转pdf执行失败"); } else { …...
RocketMQ 初步了解
RocketMQ 初步了解 前言: 近期,因公司使用 RocketMQ 作为消息队列中间件,特此了解。 RocketMQ 是阿里巴巴在 2012 年开发的分布式消息中间件,专为万亿级超大规模的消息处理而设计,具有高吞吐量、低延迟、海量…...
Mac下PyCharm快捷键
Mac键盘符号和修饰键说明 ⌘ Command⇧ Shift⌥ Option⌃ Control↩︎ Return/Enter⌫ Delete⌦ 向前删除键(FnDelete)↑ 上箭头↓ 下箭头← 左箭头→ 右箭头⇞ Page Up(Fn↑)⇟ Page Down(Fn↓)Home Fn …...
城市管网监测系统,保障城市血管生命线!
各种不同的管网线路组成了城市的供血管道,管网对于维持正常的社会生活、生产秩序和公共安全至关重要。我国城市平均漏损率达到38%,部分城市甚至超过50%,远超发达国家的平均水平(10%)。对于管道状态的监测,是…...
Web3中文|1月数据显示复苏迹象,涉及NFT、DeFi、Dapp、链游……
本期看点 1、Dapp行业概述 2、DeFi的TVL增长26.8%,有回暖迹象 3、NFT市场数据飙升,交易额达9.46亿美元 4、链游使用量占行业48% 5、与去年相比,1月份区块链漏洞损失最低 区块链领域正在多元化发展,2023年1月,从各…...
MySQL索引的介绍以及优缺点
1.索引简介 索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。 使用索引可以快速找出在某个或多个列中有一特定值的行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询操作速度的最佳途径。 索…...
Java_小项目书城
1.概述 书城的基本功能: 展示书籍上新书籍下架书籍退出应用 书城项目所涉及到的知识点: 用户交互–键盘录入分支结构,循环结构面向对象的思维,封装对象集合的使用 2.菜单的编写 这部分代码就是读取用户键盘的录入࿰…...
Unreal Engine08:Pawn的实现
写在前面 Pawn继承于Actor,增加了一些用于控制和提供玩家视角的功能,这里主要是介绍一下Pawn类的实现。 一、创建一个Pawn的C类 创建的C类也是放在Source文件夹中的Public和Private文件夹中;选择Pawn作为继承的父类;头文件中除…...
408强化(二)线性表纯享版
目录 一、顺序表(数组)和链表总览 二、考情分析 2.1 从历年考情可以看出,如果一个方法出现了第2次,一般是以下情况: 2.2 没有考过的地方 三、 共同操作或考法 3.1 多指针后移 3.2 逆置 3.3 空间换时间的操作 3.…...
ubuntu下如何使用wireshark抓包,保姆级教程
Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是截取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换。 一、安装wireshark 打开终端&…...
世界上最健康的程序员作息表!「值得一看」
昨晚看了一篇“传说中”的“世界上最健康的作息时间表”,开始纠结自己还要不要5点半起床。 都说程序员这一行,猝死概率极高,究其原因还是加班太狠、作息不规律、缺乏运动… 今天和大家分享一下这篇文章,还是非常值得参考的&#…...
Java中多继承的实现
1 问题Java是一种面向对象的只允许单继承的语言,那么怎样在Java中实现多继承呢?2 方法多层继承如果要直接继承类,子类是不可以直接多继承的,但是可以通过多层继承来实现多继承,但多层继承一般不建议超过三次。接口接口…...
蓝桥杯 stm32 USART 串口发送数据
文章代码使用 HAL 库。 文章目录 前言一、串口原理图二、CubeMX 创建工程。三、串口发送函数:四、串口助手 配置:五、详细代码:注意:连续发送数据六、printf 重定向问题代码示例:实验效果:总结前言 USART : ( Universal Synchronous/Asynchronous Receiver/Transmitter…...
Spring之AOP底层源码解析
Spring之AOP底层源码解析 1、动态代理 代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。 举个例子 public class UserService {public void test() {System.out.println("test.…...
人脸识别——景联文科技提供3D头模数据采集业务!
“拿起手机刷脸解锁、上下班考勤、支付订单,刷脸已极大地便利了我们的生活。清华大学新闻学院教授沈阳表示,中国人平均每天要暴露在各种摄像头下超过500次。人脸识别已成了我们生活中重要的一部分。由于2D人脸识别容易受到姿态、表情、光照等因素影响&am…...
怎让做淘宝网站/如何推广外贸型网站
栅栏屏障,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。 CyclicBarrier默认的构造方法是CyclicBarrier(int …...
涟水做网站/杭州seo公司排名
踏上勤奋的阶梯,方可达到智慧的高峰。只有勤奋加上智慧,才有可能实现成功的理想。一月再见,二月你好!认定了的路,再痛也不要皱一下眉头,你要知道,再怎么难走都是你自己选择的,你没有…...
如何让网页适应屏幕尺寸/江西省seo
哈哈哈哈哈哈哈哈哈哈哈哈,终于把这道题补出来了_(:з」∠)_ 来写题解啦。 _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ 哈哈哈哈哈哈,从9月16日打了这个题之后就一直在补这道题,今天终于a了,哈哈哈哈哈哈。 先…...
镇江企业做网站/学生个人网页制作代码
[关键字]:后缀数组 字符串 [题目大意]:给定n 个字符串,求出现或反转后出现在每个字符串中的最长子串。 // [分析]:和前几道题一样的做法,先见字符串和它反转后的串连在一起并用不同的字分割(小于原串的任意…...
怎么做网站注册的网页/广州网站建设技术外包
ExtJS中的布局功能很强大,常用的布局有border、accordion、fit、hbox、vbox等,Ext.Net除了将这些布局进行封装以外,更是对border进行了一些非常实用的改进,让我们来看看吧。 Ext.Net布局概述 Ext.Net中的布局是对ExtJS布局的封装&…...
网上虚拟银行注册网站/淘宝产品关键词排名查询
对于刚接触linux系统的学员来说,确实是一件比较困难的事情,造成这种局面主要原因之一是windows的设计考虑到用户的体验效果,提供了更好的用户操作效果。以至于用户接触的最多的系统,所以刚接触linux的时候会感觉很不适应ÿ…...