【C++】函数重载底层原理 C++入门(2)

发布于:2025-07-04 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

问题引入

1. 函数重载(C++)

1.1 编译链接过程

1.1.1 预处理

1.1.2 编译

1.1.3 汇编

1.1.4 链接

2. C语言中的处理

3. 总结


本篇可以解决的问题:

  • 为什么C语言没有函数重载,为什么C++有函数重载?

  • C++如何实现函数重载?

问题引入

首先回顾一下什么是函数重载?

函数重载相当于一词多义,就是说有多个同名函数,但是参数列表不同(数量、顺序、类型),会根据参数的不同而进入不同的函数,用来解决不同但类似的问题

请问下面这种情况是不是函数重载?

short Add(short left, short right) {
	return left + right;
}

int Add(short left, short right) {
	return left + right;
}

答:函数重载与返回类型没有关系,所以明显不是函数重载,在一些编译器中会报错。

而我们今天就深入探讨一下,为什么函数重载和返回类型没有关系?又为什么和参数类型、顺序、个数有关系?

1. 函数重载(C++)

因为是偏向底层的讲解,所以这里不适用VS(IDE),而是使用Linux来展现整个过程。

首先我们回顾一下学习C语言的过程中,可执行文件的生成过程?

1.1 编译链接过程

  • 预处理 -- 头文件展开,宏替换,条件编译,去掉注释

  • 编译 -- 检查语法,生成汇编代码

  • 汇编 -- 把汇编代码转换成二进制的机器码

  • 链接 -- 找调用函数的地址,链接对应上,合并到一起 合并符号表


符号表补充知识:

符号表里面有什么?

  1. 目标文件中引用的全局变量和函数

  2. 目标文件中定义的全局变量和函数

本质上符号表表达的内容?

  1. 我能提供给其他文件使用的符号

  2. 我需要其他文件提供给我的符号

1.1.1 预处理

这里我们先创建三个文件,分别是 f.h、f.cpp、test.cpp:

 

 

预处理之后,头文件被展开:

1.1.2 编译

举一个例子:

int main() {
	Add(3, 0.14);
	Add(0.141, 3);
	return 0;
}

 反汇编代码如下:

1.1.3 汇编

因为机器只能识别0、1,并不认识指令级代码,所以这一步需要将指令级代码转换成二进制的机器码。

1.1.4 链接

找调用函数的地址,链接对应上合并到一起,合并符号表。

在编译的过程中还会生成一个符号表,主要记录函数定义和函数地址的映射,在main函数的指令中,有两句指令call,call后面所跟的就是函数的名字和函数的地址。

为了更好的看清楚函数的命名规则,我们在Linux中来看一看:当函数名相同,参数不同时,他们的函数名会有一套新的命名规则。在不同的函数调用中,他们参数类型首字符带进命名规则中去了。

新的函数名:_Z 函数名长度 函数名 类型首字母

也就是图中的:

  • _Z1fid
  • _Z1fdi

1是函数名长度,f是函数名,id(类型首字母PS:整形指针的是Pi)是int和double。也注意!这里没有解释返回类型的指令,这也可以说明为什么C++的返回类型不能作为函数重载条件的原因!

2. C语言中的处理

创建三个文件:


我们再在Linux下看看C语言是如何处理函数名的

可以看出,C语言对于函数的描述只有函数名本身,并没有参数的相关信息。

我们在Linux下看看报错信息:我们创建两个f函数,我们在Linux下用gcc编译看报错信息,我们发现这时就会报错说函数命名发生冲突。

3. 总结

  • C++支持重载的原因是,再生成符号表示,对于函数的命名规则有了新的变化:_Z+函数名长度+函数名+类型首字母
  • 而在新的命名规则下,依然没有返回类型的相关信息,因此返回类型对于函数重载没有影响
  • C语言对于函数命名的处理中,只有函数名而不涉及其他参数,所以C语言并不支持函数重载

 


网站公告

今日签到

点亮在社区的每一天
去签到