c++函数重载机制实现原理

来源:互联网 发布:aspen软件安装包 编辑:程序博客网 时间:2024/06/05 20:12

一、c++函数重载的定义:

同一作用域类,一组函数的函数名相同参数列表不同(参数个数不同/参数类型不同)返回值可同可不同

二、函数重载的作用:

重载函数通常用来在同一个作用域内 用同一个函数名 命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。

三、函数重载是一种静态多态:

(1)多态:用同一个东西表示不同的形态;
(2)多态分为:
静态多态(编译时的多态)
动态多态(运行时的多态);
(3)函数重载是一种静态多态;

四、c++函数重载的原理:

(一)
编译器在编译.cpp文件中当前使用的作用域里的同名函数时,根据函数形参的类型和顺序会对函数进行重命名(不同的编译器在编译时对函数的重命名标准不一样)但是总的来说,他们都把文件中的同一个函数名进行了重命名;

  • 在vs编译器中:
    根据返回值类型(不起决定性作用)+形参类型和顺序(起决定性作用)的规则重命名并记录在map文件中。
  • 在linux g++ 编译器中:
    根据函数名字的字符数+形参类型和顺序的规则重命名记录在符号表中;从而产生不同的函数名,当外面的函数被调用时,便是根据这个记录的结果去寻找符合要求的函数名,进行调用;

五、为什么c语言不能实现函数重载

编译器在编译.c文件时,只会给函数进行简单的重命名;具体的方法是给函数名之前加上”_”;所以加入两个函数名相同的函数在编译之后的函数名也照样相同;调用者会因为不知道到底调用那个而出错;

六、实验说明:

(一)在C语言中,如果两个函数的函数名相同,不管形参和返回值是否相同,程序运行都会发生错误
在.c文件中;写出下列代码,在vs2008运行出错:

#include<stdio.h>int Add(int a,int b){   return a+b;}float Add(float a,float b){    return a+b;}int main(){    Add(10,20);    Add(20.0f,30.0f);    return 0;}

运行结果:报错—函数“int Add(int,int)”已有主体
错误原因:
程序从编译到运行出结果几个阶段。其中一个阶段提到生成符号表
我们来看一下上边的函数成的符号表。符号表是在.map文件里,在vs里默认不显示符号表文件。要想显示出来,这样设置:
工程名右击—>属性—->配置属性—->链接器—–>调试—->生成映射文件—>选择是;
上边写有两个同名函数的c程序中根本编译不通过(报错:Add函数已有主体)就无法生成符号表。所以,我去掉一个函数,让程序编译通过,看看函数名在符号表中的命名
这里写图片描述
通过这个我们可以得出,c程序中的Add()函数在符号表中的重命名就是函数名前边加个下划线。所以如果一个c程序中出现了同名函数,他们在符号表中的命名一样,这样调用时就出现了冲突。

(二)将上面的代码在改为.cpp文件,编译之后在map中查看两个Add()函数的名字;
这里写图片描述
这里我们可以看出,在.cpp文件中,虽然两个函数的函数名一样,但是他们在符号表中生成的名称不一样。
‘?’表示名称开始,‘?’后边是函数名“@@YA”表示参数表开始,后边的3个字符分别表示返回值类型,两个参数类型。“@Z”表示名称结束。
由于在.cpp文件中,两个函数生成的符号表中的名称不一样,所以是可以编译通过的。

那么既然c++编译器和c编译器对函数名的重命名规则不一样;
那么怎么在一个.cpp文件中调用.c文件的函数?
以前写的一篇相关文章
(三)不同的编译器对c++代码的函数重命名规则不一样;
下面看看在linux下g++编译器对相同代码函数名的重命名;

cpp文件在linux虚拟机里需要用g++编译。
安装g++很简单。命令: yum install gcc gcc-c++
安装好了之后就可以了。运行程序之后,使用命令:objdump a.out -t > test.out
-t是表示生成符号表,最后是将生成的符号表用重定向符号放在test.out文件。打开test.out文件,就会发现,整形数相加的函数Add(int a,int b)生成的符号表中,Add函数名被记录为_Z3Addiii,其中。_Z表示符号表名称开始, 3代表函数名的字符个数iii代表按顺序三个形参的类型;
可以看出:同样的.cpp文件在window的vs2008编译器和linux的g++编译中,相同的函数名进过编译之后的重新命名不一样;

原创粉丝点击