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

原文链接:https://blog.csdn.net/gogogo_sky/article/details/72807123

一、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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果:报错—函数“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++编译中,相同的函数名进过编译之后的重新命名不一样;



猜你喜欢

转载自blog.csdn.net/cherisegege/article/details/80470075