您现在的位置是:首页 >技术交流 >【C++】函数重载及实现原理网站首页技术交流
【C++】函数重载及实现原理
🔥🔥 欢迎来到小林的博客!!
🛰️博客主页:✈️林 子
🛰️博客专栏:✈️ 小林C++之路
🛰️社区 :✈️ 进步学堂
🛰️欢迎关注:👍点赞🙌收藏✍️留言
什么是函数重载?
函数重载就是允许出现多个同名函数,但是参数类型,参数顺序,参数数量不同才能构成函数重载。
我们先来看看以下这段代码,用C语言编译会怎么样。
#include<stdio.h>
void fun(int i)
{
printf("fun(int i )
");
}
void fun(int i, double d)
{
printf("fun(int i, double d)
");
}
int main()
{
fun(1);c
fun(1, 1.1);
}
我们会发现出现这样的错误。
这是因为C语言再检测时发现了同名函数。那如果我们把文件改成cpp形式再编译呢?
我们会发现cpp可以打印出来。
这是因为C++支持函数重载,而函数重载就是可以同时存在多个函数名相同的函数,但是必须至少满足以下三点的其中一点。
1. 函数参数数量不同
2. 函数参数类型不同
3. 函数参数顺序不同
例如:
//以下两个fun函数数量,类型不同
void fun(int i)
{
printf("fun(int i )
");
}
void fun(int i, double d)
{
printf("fun(int i, double d)
");
}
//以下两个a函数,数量相同,但是参数顺序不同..也可以归纳为类型不同
void a(int i, double d)
{
;
}
void a(double d, int i)
{
;
}
//以下两个b函数,参数类型不同
void b(int i) {
;
}
void b(double d)
{
;
}
为什么要有函数重载?
我们知道了函数重载是什么之后,那么为什么要有函数重载?比如我要写两个函数,一个函数可以对整形进行加法运算,而另一个函数要对浮点型进行加法运算。那么我们在C语言中只能这样写。
#include<stdio.h>
int addI(int x, int y)
{
return x + y;
}
double addD(double x, double y)
{
return x + y;
}
int main()
{
addI(10,20);
addD(10.5, 20.5);
}
但是在C++中,支持函数重载,我们可以这样写。
#include<stdio.h>
int add(int x, int y)
{
return x + y;
}
double add(double x, double y)
{
return x + y;
}
int main()
{
add(10,20);
add(10.5, 20.5);
}
有没有发现支持了函数重载之后,add 有自动类型推导 的作用? 这就是函数重载的作用。避免对各种各样功能相同,但是类型不同的函数取不同的函数名。这样记起来也麻烦,用了函数重载之后,那么只需要记住一个函数即可。
函数重载的原理
那么函数重载是如何实现的呢?那我们要知道.c/cpp 源程序在生成可执行程序时要经历的四个阶段。
1.预处理 : 负责头文件展开,宏替换,条件编译,去掉注释等…
2. 编译 : 检查语法,语法没有错误后,把C代码转换为汇编指令
3. 汇编 : 将汇编指令转换为二进制机器码
4.链接 : 合并符号表
那么我们就在每个阶段来观察一下这个函数,接下来将会在linux系统下演示。
首先,我们先写一个fun.c的源文件
#include<stdio.h>
void fun(int i)
{
printf("fun(int i )
");
}
void fun(int i ,double d)
{
printf("fun (int i , double d)
");
}
int main()
{
fun(1);
fun(1,1.1);
return 0;
}
然后执行命令 gcc -E fun.c -o fun.i
将fun.c进行预处理后生成一个.i文件
然后我们发现编译器并没有报错,那么说明冲突不是在预处理阶段产生的。我们来看看fun.i的内容。
我们会发现,和C语言代码并没有其他区别,区别就是头文件展开了。
接下来,我们再执行 gcc -S fun.i -o fun.s
将预处理过的.i文件进行编译,转换为汇编代码。
然后我们就会发现编译出错,那么说明冲突是编译时产生的。那么我们换成.cpp文件来看。
我们把fun.c 改成funcpp.cpp, 然后分别执行 g++ -E funcpp.cpp -o funcpp.i
和 g++ -S funcpp.i-o funcpp.s
我们会发现编译没有问题,那么我们来查看一下汇编代码。
我们发现 fun(int i)函数实际修饰名是_Z3funi。
那么我们再看看fun(int i ,double d)的函数名是什么。
fun(int i ,double d)的实际修饰名是 _Z3funid。
在Linux操作系统下, 这个3表示函数名的字符串长度,后面跟上函数名,之后就是参数类型,int 为i,double为d。
也就是说虽然 fun(int i ,double d)
和 fun(int i ,double d)
函数名相同,但是在修饰之后。实际上的函数名是_Z3funi
和 _Z3funid
。所以并不存在冲突问题。
那么为什么C语言不行呢?那么我们写一个正确的C语言代码,重复上面步骤,看看C语言的实际函数名是什么。
这是一段正确的C语言代码。
#include<stdio.h>
void fun(int i)
{
printf("fun(int i )
");
}
int main()
{
fun(1);
return 0;
}
随后进行预处理和编译。
编译后我们查看fun.s文件,会发现函数fun实际上就是函数fun。没有其他修饰规则,所以就造成了函数名冲突问题。
总结
函数重载本质就是对函数名进行了修饰,允许函数名相同,但是参数数量,顺序,类型不同的函数同时共存。虽然表面上看起来这个函数名是这个函数的函数名,但是在编译后函数名会被处理修饰。所以每个重载的函数真正意义上的函数名是不同的。而C语言则没有加修饰,函数名就是函数名,所以就会出现冲突编译报错的情况。