CPP勇攀顶峰之路3——函数重载

一、定义

  • cpp允许同一个作用域中的某个函数(函数重载)和运算符(运算符重载类)指定多个定义;
  • cpp允许在同一个作用域内可以声明几个功能不同的同名函数,形参列表(参数个数或类型或类型顺序)必须不同。
  • 不能仅通过函数的返回值的不同来重载函数;
  • 调用一个重载函数或重载运算符时,编译器通过把你使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择合适的重载函数或重载运算符的过程,称为重载决策。

二、底层原理

1. 为什么c语言不支持函数重载?

  • 程序在预编译结点都会经历预处理、编译、汇编、连接、生成可执行程序的过程,值得一提的是,在汇编过程中编译器会收集全局符号并生成全局符号表(将符号和其对应地址一一对应的表格成为符号表)。
  • 每个文件里都会产生本文件的符号表,对于暂时找不到地址的函数(比如只是一个函数的声明),它的地址是一个没有意义的填充值:

在汇编的过程中我们生成了多个符号表,但最后只能合并为一个符号表,所以在连接过程中要对符号表进行合并。在合并过程中发现Add函数出现了两次,就涉及了重定位——Add函数有效的地址值就会作为Add函数最终的地址值。所以在C语言中两个重名函数的地址都是有效值,所以在重定位的时候就会产生冲突和歧义。

2. Cpp是如何支持函数重载的?

C语言符号表中出现了两个具有有效地址的同名函数名,所以发生了冲突,只要能解决函数名冲突的问题,相应的就可以实现函数重载的效果——Cpp对写入符号表的函数具有一个修正的过程

在linux下观察反汇编的效果,发现函数名’f’已经被修正为 ‘_Z1fid’,我们可对Linux下的命名规则做如下总结:

_Z + 函数名长度 + 函数名 + 各个形参类型首字母的小写

(补充:int* 会修正为Pi)

举一反三,上面函数的函数名就会被修正为 _Z1fdi。既然函数名可以区分开来了,那么实现函数重载就不是问题了。

三、如何保证.c代码和.cpp代码之间的可移植性

1. Cpp程序调用C静态/动态库

C程序可以调用C的静态/动态库,C++程序可以调用C++的静态/动态库,那么能不能实现交叉调用呢?

 这里最大的鸿沟在于C符号表的函数名就是原来的函数名,而C++中的则是经过修饰过的函数名,如果直接用C++程序去调用C的静态/动态库中的函数,是找不到对应函数的。所以在这里,extern C就派上用场。

   有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,它的作用是将它所包含的函数采用C语言的规则进行编译链接,从而不会对函数名进行修正。

2. C程序调用Cpp静态/动态库

对.cpp文件动刀——此时我们在即将调用的C++库中加入这样一段条件;

  1. #ifdef __cplusplus
  2.  #define EXTERN_C extern "C"
  3. #else
  4.  #define EXTERN_C
  5. #endif 
  6. EXTERN_C int add(int a, int b);

代码剖析:

__cpluscplus是C++项目默认设置的宏定义标识符,我们用它来判断是不是C++程序

在C++库中,EXTERN_C被解释成 extern “C” ,也就意味着C++库中函数名不会被修正

在C程序中,EXTERN_C被解释为空,不起到任何作用

在链接的时候,C程序和C++库中的函数名相同,在合并符号表时就不会出错

如果没有条件编译指令,只有 #define EXTERN_C extern “C” ,那么会因为C程序识别不了 extern “C” 而报错

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值