函数重载的诞生
在大型程序项目中,一般都是分工合作的,此时设计出了大量的函数,如果过两个程序员设计出了相同的函数名,即使函数里面的内容不一样,在C语言中编译也会出现链接错误,甚至你的函数名与包含的库函数中的名字相同,也一样会出现错误,所以c语言不允许同名函数存在。于是c++祖师爷本贾尼博士提出了函数重载的概念。
函数重载的概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。如果是不同得命名空间,就不一是一个作用域,就不能说这是函数重载了。
为什么需要函数重载
试想一下。如果没有函数重载,如在 C 中,你必须要这样去做:为这个 print 函数取不同的名字,如 print_int、print_string。这还只是两种情况,如果是很多个的话,就需要为实现同一个功能的函数取很多个名字
,如加入打印 long 型、char*、各种类型的数字等等。这样做很不友好!
类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实现实例化不同的对象,那是相当的麻烦!
操作符重载,本质上就是函数重载,它大大丰富了已有操作符的含义,方便使用,如 + 可用于连接字符串等!
c++中使用函数重载的三种类型(重点)
1、参数类型不同,也就是int long char这些,只要类型不一样,构成函数重载,函数名即使相同,依然可以按调用程序员预想之中的函数,而不会弄混
2、参数个数不同,也就是形参的个数只要有区别,也是可以构成函数重载的。
3、参数类型顺序不同,实际上两个函数的参数你能看出区别,就能构成函数重载。
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
函数重载会不会使得程序运行变慢呢?
不会,因为这一步是在编译阶段完成,编译阶段确实会变慢,但是不影响运行。
函数重载的原理
- 实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们
可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标
文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么
怎么办呢?
- 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就
会到b.o的符号表中找Add的地址,然后链接到一起。(老师要带同学们回顾一下)
- 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的
函数名修饰规则。
- 由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使
用了g++演示了这个修饰后的名字。
- 通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度
+函数名+类型首字母】。
结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。
采用C++编译器编译后结果
结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参
数类型信息添加到修改后的名字中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。