函数重载你真的了解吗?

简介: 函数重载你真的了解吗?

1.什么叫函数重载?

函数重载(Function Overloading)是指在同一个作用域内,允许定义多个具有相同名称但参数列表不同的函数。具体而言,函数重载允许你定义同名的函数,但这些函数应该有不同的参数类型、参数个数或者参数顺序。

举例

上述代码中有两个名为Print的函数,虽然名字一样,但是参数类型不一样。在c语言中会认为这两个是一个函数,后一个定义的会覆盖前面一个。在c++中函数重载的概念引入之后便认为这两个函数是不同的两个函数,并会根据传参类型自动选择相应的函数,由此一来我们的代码会变得更加灵活和易读

2.参数不同构成函数重载

值得注意的是,如果仅仅是函数返回值不同是无法构成函数重载的。在函数调用时,编译器会根据实际传递的参数类型来确定调用哪个函数,而不是仅仅依赖于返回值类型。

3.函数重载的原理

为什么c语言不支持函数重载而c++支持呢?

在c/c++中,一个程序要想运行起来需要经历以下几个阶段:预处理、编译、汇编、链接。

预处理会将.c/.cpp文件中的代码经过头文件展开、去除注释、宏替换、条件编译转换成 .i文件

编译会将 .i 文件中的代码翻译成汇编代码,生成 .s文件

汇编会将 .s中的汇编代码翻译成二进制指令,生成 .o文件(也叫目标文件)

链接会将程序所有的 .o 文件进行链接生成 .exe后缀的可执行文件

其中,在链接这个阶段会进行合并段表、符号表的合并和符号表的重定位等行为。简单来说,链接操作通过合并这些符号表等实现了程序中各个文件的连接,也就是能在一个文件中通过符号表找到另一个文件定义的函数地址并执行这个函数

1.实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们

可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标

文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么

怎么办呢?

2. 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就

会到b.o的符号表中找Add的地址,然后链接到一起。(老师要带同学们回顾一下)

3. 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。

4.函数名修饰规则

函数名修饰(Name Mangling)通常是指编译器对函数名进行的一些变换或修改,以便区分同名函数或支持函数的重载。在C语言中,函数名修饰是相对较简单的,因为C语言本身不支持函数的重载。

4.1对比c/c++处理函数名

C语言中的函数名不会被修饰: 在C语言中,函数名不会被编译器修改或添加任何前缀或后缀,因为C语言本身不支持函数的重载。因此,C语言的函数名在源代码中的写法和编译后的二进制代码中是一样的。

C++语言中的函数名修饰: C++支持函数的重载,因此编译器需要在编译阶段对函数名进行修饰,生成唯一的函数名以区分不同的函数。修饰的方式通常包括添加函数参数类型、参数个数等信息。

4.2c++具体是怎么修饰函数名的呢?

以linux举例,在Linux中,g++ 编译器使用 C++ ABI (Application Binary Interface) 标准,其函数名修饰规则是按照 Itanium C++ ABI 来进行的。以下是一些基本规则:
  1. 函数名修饰格式: C++ 编译器根据函数的参数类型、参数个数、以及一些其他信息生成一个唯一的函数名。这个过程称为 name mangling。修饰后的函数名通常包含原函数名以及一些用于标识参数类型和个数的信息。
  1. 名称修饰的参数类型表示: 常见的参数类型表示包括基本数据类型、指针、引用等。例如,int 类型可能用 i 表示,double 类型可能用 d 表示。
  1. 参数个数和其他信息: 修饰还包括参数的个数和其他一些信息,以区分函数重载和模板特化等情况。

观察以下函数

void myFunction(int x, double y);//修饰后的函数名为:_Z10myFunctionid

4.3用汇编代码查看函数名是否被修饰

观察以下代码

以上代码是在linux中的vim编译器运行的,具体的操作指令大家无需了解。我们只需要知道gcc是编译c语言的编译器,而g++是编译c++代码的编译器。我们现在用两种方式去编译同一份代码,并观察其 汇编阶段生成的 .s 文件,这样我们就能在汇编层面观察到函数名被修饰的样子。

用gcc编译

用g++编译

我们可以看到,add函数名被修饰成了_Z3addii 其中后缀"ii" 指的是两个参数的类型。这样一来,两个函数的名字名即使相同,我们也能因为其参数不同生成两个不同的“函数名”。

5.总结

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修
饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载

同时需要注意的是,函数名修饰的具体的修饰规则可能会因编译器版本、编译选项、操作系统等因素而有所不同。在实际的应用中,除非涉及到与其他语言或库的交互,否则大多数情况下不需要深入了解或处理函数名修饰。

相关文章
|
资源调度 Kubernetes 应用服务中间件
Kubernetes Scheduler Framework 扩展: 2. Binpack
# 前言 ## 为什么需要Binpack功能? Kubernetes默认开启的资源调度策略是`LeastRequestedPriority`,消耗的资源最少的节点得分最高,优先被调度。这样的资源选择情况有可能导致较多的资源碎片,如下图所示,两个节点各剩余1GPU的资源,导致申请2GPU的作业无法调度,导致整体资源使用率下降。 如果使用的资源调度策略是Binpack,优先将节点
2251 0
VSCode:code helper进程导致Mac的CPU使用率很高
VSCode:code helper进程导致Mac的CPU使用率很高
1864 0
VSCode:code helper进程导致Mac的CPU使用率很高
|
缓存 网络协议 Java
【JavaEE】——TCP应答报文机制,超时重传机制
TCP报头图解,传输的可靠性,应答报文机制,超时重传机制,数据缓存区去重机制和排序机制
【JavaEE】——TCP应答报文机制,超时重传机制
|
消息中间件 存储 Kafka
RocketMQ 工作原理图解,看这篇就够了!
本文详细解析了 RocketMQ 的核心架构、消息领域模型、关键特性和应用场景,帮助深入理解消息中间件的工作原理。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
RocketMQ 工作原理图解,看这篇就够了!
|
网络架构
YOLOv5改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv5(超级轻量化精度更高)
YOLOv5改进 | 2023主干篇 | 利用RT-DETR特征提取网络PPHGNetV2改进YOLOv5(超级轻量化精度更高)
907 0
|
编译器 程序员 C++
函数重载(function overloading)
函数重载(function overloading)是编程语言中一种支持多个同名函数的特性,这些函数在参数列表(参数类型和数量)上有所不同。当调用一个重载函数时,编译器会根据函数参数列表的具体情况进行匹配,然后调用相应的函数实现。
727 5
|
JavaScript 数据可视化 图形学
iCraft Editor - 助你轻松绘制出色的立体架构图
iCraft Editor是一款创新工具,专为绘制立体架构图设计,带来直观且吸引人的3D视觉体验。它简化了复杂系统的表达,支持自由旋转与缩放,让用户从多角度审视设计。简洁界面与丰富图形库让操作变得简单快捷,即使是新手也能迅速上手。iCraft Editor支持子场景嵌套及外部模型导入,适用于软件架构设计、系统部署维护等多种场景,提升沟通效率。无需编程基础,即可在线免费使用,轻松实现复杂设计的可视化。开启3D新视角,让您的创意无限延伸![官网](https://icraft.gantcloud.com)
3150 1
iCraft Editor - 助你轻松绘制出色的立体架构图
|
Linux 数据安全/隐私保护
【Deepin 20 系统】Linux系统在开机时未进入系统前进入命令行界面(终端)
如何在Deepin 20系统启动时进入命令行界面(终端),通过在GRUB界面中编辑内核启动参数来引导系统进入多用户文本模式(运行级别3)。
1323 1
YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)
YOLOv8打印模型结构配置信息并查看网络模型详细参数:参数量、计算量(GFLOPS)

热门文章

最新文章

下一篇
开通oss服务