函数重载定义
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表中的参数个数、类型、顺序必须不同,常用来处理实现功能类似数据类型不同的问题。
函数重载条件
a.参数类型不同
void Print(int a, int b)
{
cout << " Print(int a, int b) " << endl;
}
void Print(double a, double b)
{
cout << " Print(double a, double b) " << endl;
}
b. 参数个数不同
void Print(int a, int b)
{
cout << " Print(int a, int b) " << endl;
}
void Print(int a, int b, int c)
{
cout << " Print(int a, int b, int c) " << endl;
}
c. 参数顺序不同
void Print(int a, int* b)
{
cout << " Print(int a, int* b) " << endl;
}
void Print(int* a, int b)
{
cout << " Print(int* a, int b) " << endl;
}
函数重原理
为了方便展示函数重载的原理,我们在Linux环境下编写3个文件:头文件func.h源文件func.c和test.c文件
我们回顾一下一个程序的编译过程:
- 预处理-> 头文件展开、宏替换、条件编译、去注释,生成.i文件
- 编译-> 语法分析、词法分析、语义分析等,生成.s文件
- 汇编-> 形成符号表、汇编代码转换成二进制机器码,生成.o文件
- 链接-> 合并段表、符号表合并和符号表重定位
在链接过程中,链接器看到test.o调用f()函数,但是没有f()函数的地址,就会到func.o的符号表里找f()函数的地址,然后链接到一起。那么编译器会使用哪个名字去func.o里去找f()函数地址呢,
- 我们通过反汇编查看C编译器的函数名修饰
我们分别对f()函数以及f(10)函数进行调用,可以看到C语言编译器完成编译后,函数名字的修饰没有发生改变。
总结:C语言不支持函数重载,因为在编译的时候,两个重载函数的函数名相同,在func.c符号表中存在歧义和冲突,其次,链接的时候也存在歧义和冲突,因为他们都是直接使用函数名去标识和查找,而重载函数的函数名相同,故C语言不支持函数重载
下图是C语言编译器对函数重载的报错:
- 我们还是调用f()函数和f(10)函数,再来看一下C++编译器对函数名的修饰规则
总结:
1. 可以清楚的看到,在Linux下,采用g++编译完成后,函数的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。
2. 有了函数名的修饰规则,只要参数不同,func.o符号表里面重载的函数就不存在二义性和冲突了。
3. 链接的时候,tset.o的main函数里面去调用两个重载的函数,查询地址时,也是明确的,链接时使用修修饰后的函数名进行查找。
【函数名修饰规则:Z+函数长度+函数名+类型首字母】,不同编译器有不同的函数名修饰规则