前言
今天小编给大家带来的是C++中关于函数重载的内容,和C语言不一样,函数重载是C语言特有的,那么该功能实现的底层原理是什么呢?请大家和我细细往后看。
函数重载
1.函数重载的概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。(注意:返回值类型在函数重载中是没有起到作用的)
这里我给大家举一个例子说明一下:
//参数类型不同 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语言中,以上的写法一定会出现定义冲突的情况,那么在C++中该是否能运行呢?这里我们直接看结果:
这里我们发现,当我们函数名重名时我们这里由于,参数类型不同,参数个数不同,参数类型顺序不同,我们是可以运行的。那么这里我们底层原理是什么呢?大家接下来请继续看小编对其的有关介绍。
2.C++支持函数重载的原理--名字修饰(name Mangling)
在介绍名字修饰时我们就要想到一个程序执行时的:预处理、编译、汇编、链接。这几个过程。至于对这个过程,小编以后会给大家进行详细介绍,大家这里先简单的配合理解一下。
这里我们只需要知道这几个过程执行中的内容是:
这里我们还需要注意一下每个阶段结束后就会参数对应文件后缀的名字,预编译结束后产生的是.i的后缀,编译后产生的是.s的后缀,汇编结束后会产生.o的的文件。那么这里我们看具体过程:
这里我们以C语言程序的例子为例:
1. 实际项目通常是由多个头文件和多个源文件构成,当前main.c中调用了sum.c 中定义的sum 函数时,编译后链接前,main .o 的目标 文件中没有sum 的函数地址,因为sum 是在sum .c 中定义的,所以sum 的地址在sum .o 中。那么 怎么办呢?
2.所以链接阶段就是专门处理这种问题, 链接器看到main .o 调用sum ,但是没有sum 的地址,就
会到sum .o 的符号表中找sum 的地址,然后链接到一起。
说到这里我想大家应该都明白了,实际上我们到链接的阶段时我们识别对应函数时通过编译后的会对产生对应的函数名,以及记录其地址,对于C语言我们并不会因为函数参数进行修饰,但是C++却有其修饰规则(由编译器决定)。
这里由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使
用了g++演示了这个修饰后的名字:
通过下面我们可以看出gcc的函数(C语言)修饰后名字不变。而g++的函数(C++)修饰后变成【_Z+函数长度
+函数名+类型首字母】
C语言:
这里大家先不用怎么看到此类界面,小编之后会在讲解编译,链接的过程中给大家仔细详解,这里大家看到在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。着也就是C语言没有函数重载的原因。
C++语言:
这里我们可以发现 在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参 数类型信息添加到修改后的名字中。
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修 饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。
这里给大家讲解一下windows下的命名修饰规则:
这里大家做简单了解就行,不需要着重掌握。