目录
- 函数重载
- 函数重载是怎样实现的
函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
要注意的是:只有函数名相同,形参不同(个数\类型\类型顺序不同)才能构成函数重载
而函数名相同,返回值不同的函数不构成函数重载
返回值类型与函数是否重载无关
- 参数类型不同
int add(int a, int b)
{
cout << "int:" << a + b << endl;
return a + b;
}
double add(double a, double b)
{
cout << "double:" << a + b << endl;
return a + b;
}
int main()
{
add(1,1);
add(1.1,2.2);
}
- 参数个数不同
void fun(int a)
{
cout << a << endl;
}
void fcun(int a, int b)
{
cout << a <<" "<< b << endl;
}
int main()
{
fun(1);
fun(1,2);
}
- 参数类型顺序不同
这里注意:是参数类型顺序不同,而不是参数名顺序不同
int f(int a,double b)
和int f(int b,double a)
是不构成重载的
void ff(int a, char b)
{
cout << a << " " << b << endl;
}
void ff(char a, int b)
{
cout << a << " " << b << endl;
}
int main()
{
ff(10,'a');
ff('a',10);
}
以上三个情况就是各种类型的函数重载
其实还有一种情况,就是当重载和缺省在一起时:
void fff()
{
cout << 1 << endl;
}
void fff(int a = 0)
{
cout << a << endl;
}
上面2个函数都可以通过编译
当我们使用实参对缺省参数赋值fff(1)
,可以正常运行
但是无参调用时会出现歧义,会报错
fff()
,编译器不知道是要调用无参的那么函数还是调用缺省参数函数,发生冲突,无法运行
函数重载是怎样实现的
C语言不支持函数重载,而C++却能支持,C++是如何支持的呢?
这其实是在编译链接过程中,利用函数名修饰规则实现的
我们先来看一下编译链接的过程,如果我们在test.h
中声明了函数,在test.cpp
中实现,在_test.cpp
文件中调用
实验代码如下:
test.h
#include <iostream>
using namespace std;
int add(int a, int b);
double add(double a, double b);
test.cpp
#include "test.h"
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
_test.cpp
#include "test.h"
int main()
{
add(1,1);
add(1.1, 2.2);
return 0;
}
编译链接过程如下图:
调用函数都会被转换成call
+一个地址,这个地址就是函数的地址
所以,这段代码在编译过程中,需要call
2次,本来call
需要去找到函数的地址,但是函数的定义在test.cpp
文件中,地址也在test.i
文件中,当前还未链接,所以还找不到地址
下面接着编译链接,在链接时,会生成一个符号表,这里面有函数名和其地址,这时2个文件是链接在一起的了
,之后就会进行找函数地址操作
但是C语言中,规定的是通过函数名进行寻址,因为这里有2个姓名相同的函数名,所以找不到正确的地址
所以C语言才不支持函数重载
下面,我们也通过linux系统,给;能够更方便得观察到函数名修饰规则
我们先在linux环境下创建一个c语言文件test.c
然后我们通过下面这些操作可以看到这个代码的汇编代码:
从汇编代码中找到调用func
函数的部分:
这也证实了C语言是通过函数名进行寻址的
下面我们看一下C++是什么样的
先写一个cpp文件
然后还是观察它的汇编代码
可以看见汇编代码中,2个func
的名字变了,这里不是func
了
这其实就是函数名修饰规则
第一个调用的函数名是
_Z4funci
-Z
是编译器规定的长度
4
是指函数名func
的长度
func
就是原函数命
最重要的就是i
,它jiusint
类型的缩写
同理,第二个函数名最后的id
就是int
和double
类型的缩写
这里也能看出来为什么饭返回值不同不会构成函数重载?
因为返回值不会进入到函数名修饰规则里
参数会进入函数名修饰规则里,参数不同,最后函数名也不同
所以到这里就理解了为什么C++支持函数重载了
最后我们思考一个问题
如果我们把函数名修饰规则修改,允许返回值的类型以某种方式进入规则中,那么返回值不会是否会导致函数重载?
答案是也不可以
因为如果遇到如下的代码,2个函数的函数名相同,没有参数或参数都相同,只有返回值不同
int a()
{
printf("int\n");
}
double a()
{
printf("double\n");
}
int main()
{
a();
return 0;
}
这样到了汇编阶段,调用函数时返回值类型是体现不出来的,所以编译器也不知道到底是调用哪个函数
所以不论怎样,返回值类型不同不会导致函数重载