【C++】C++函数重载(详)

C++有三大定义一定要分清楚:重载,重写(类中子类覆盖基类),重定义(隐藏)
今天自己给自己挖坑,所以查资料复习了一遍,先说重载,其他两种后面再说。

1. C++函数重载的定义
概念:同一作用域下,函数名相同,函数参数个数不同,参数类型不同,参数位置不同,这样的一些函数叫做函数重载.
这时候可能有人会问,返回值呢,函数返回值不是那么重要吗?
咳咳,首先,C++调用函数是可以忽略其返回值的,跟C有很大的区别,感兴趣可以自己写相同的程序在C和C++中run一下。

2. 为什么要有函数重载?作用是什么?
首先,C++三大特性之一多态:调用相同的接口/方法,有不同的实现。函数也一样,有这种特性,所以就体现在了函数重载。
作用:因为定义多个函数名会分配多个空间,如果仅仅只是因为其中有一点改动,完全没必要定义多个函数名,浪费资源,所以函数重载就是解决这个问题,避免了名字空间的资源浪费。

3. 函数重载(静态多态)
在C++中多态有两种表现形式:
(1)、运行时多态(动态多态/动态联编)(2)、编译时多态(静态多态/静态联编)
函数重载就属于编译时多态。

4. 函数重载的原理
编译器在编译.cpp文件中当前使用的作用域里的同名函数时,根据函数形参的类型和顺序会对函数进行重命名(不同的编译器在编译时对函数的重命名标准不一样)但是总的来说,他们都把文件中的同一个函数名进行了重命名;
在vs编译器中:
根据返回值类型(不起决定性作用)+形参类型和顺序(起决定性作用)的规则重命名并记录在map文件中。
在linux g++ 编译器中:
根据函数名字的字符数+形参类型和顺序的规则重命名记录在符号表中;从而产生不同的函数名,当外面的函数被调用时,便是根据这个记录的结果去寻找符合要求的函数名,进行调用;

5. 为什么C语言不能实现函数重载?
这里就是编译器的处理方式不同了。
首先,C编译器在编译函数时,只是给函数简单的重命名,在函数名前加上“_”,所以函数在编译时,相同名字的函数,编译之后是一模一样,所以,函数调用时就会出现所谓二义性。

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

#include <stdio.h>
#include <stdlib.h>

int CainADD(int a,int b)
{
	return a + b;
}

double CainADD(double a,double b
{
	return a + b;
}

int main()
{
	CainADD(10,20);
	CainADD(10.1,20.1);

	system("pause");
	return 0;
}

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

但是在C++中则不同,C++中编译时,编译器会以?’表示名称开始,‘?’后边是函数名“@@YA”表示参数表开始,后边的3个字符分别表示返回值类型,两个参数类型。“@Z”表示名称结束。 (嗯,没图,结论都是资料查的,暂时不会看汇编,尴尬。)
由于在.cpp文件中,两个函数生成的符号表中的名称不一样,所以是可以编译通过的。

那么既然c++编译器和c编译器对函数名的重命名规则不一样;
那么怎么在一个.cpp文件中调用.c文件的函数?
这个问题,给你们看下代码吧。

//C++编译器
//防止头文件重复包含
#pragma  once
 
#ifdef __cplusplus
extern "C"
{
#endif
 
//需要按C标准编译的代码
 
#ifdef __cplusplus
}
#endif

不同的编译器对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函数名被记录为_Z7CainAddii,其中。_Z表示符号表名称开始, 7代表函数名的字符个数,ii代表按顺序两个形参的类型;
可以看出:同样的.cpp文件在window的vs2015编译器和linux的g++编译中,相同的函数名进过编译之后的重新命名不一样;

函数重载就说到这里,事实证明,对于C程序员来说,会读汇编是多么的重要,所以,即使开始很难,但是一定要去尝试,不然你连说难的资格都没有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cain Xcy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值