C++函数重载


什么是函数重载?

函数重载即为允许在同一作用域内,一组函数可以拥有相同函数名,不同的参数(参数个数,大小),这组函数就叫做重载函数。


注意:重载函数必须在同一作用域内,不在则不算。


两个重载函数:

1、函数名相同;

2、参数列表不同,从参数类型和个数上体现;

3、返回值可同可不同;


重载函数的作用?


1、重载函数通常被用来命名一组功能相同的函数,从而实现用同一个函数操作不同的参数。与C相比,大大提升了效率。

例如下面这个例子,我们定义两个add函数分别操作int与float。


#include<iostream>
using namespace std;
int add(int x,int y)
{
  return x+y;
}
float add(float x,float y)
{
  return x+y;
}
int main()
{
 int a = 1;
 int b = 2;
 float c = 1.2;
 float d = 2.1;
 cout<<add(a,b)<<endl;//调用add(int,int)
 cout<<add(c,d)<<endl;//调用add(float,float)
 system("pause");
 return 0;
}

2、 类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实例化不同的对象,那是相当的麻烦!

3、操作符重载,丰富了已有操作符的含义。


函数重载是如何实现的?

当一组函数函数名相同时,编译器如何去决定调用哪个函数呢?这里就涉及到了一个如何解决命名冲突的问题。

我们可以做一个实验,写一组重载函数,分别在Linux和Windows下运行并查看它们的反汇编,看一下重载函数是如何重命名的。


代码选用(重载函数的作用1中的例子)


Linux下:

执行命令 objdump -d a.out >test.txt  反汇编,并将结果重定向到test.txt中。 查看test.txt文件。





打开test.txt文件后:

我们发现 int add(int,int)被重定义为----------------> (_Z3addii);

                   float add(float,float)被重定义为----------->(_Z3addff);




    


通过这次实验我们可以发现,编译之后,重载函数的名字不在相同,这样就不存在命名冲突的问题了。那么编译器是如何进行函数重命名呢?


int add(int,int)被重定义为----------------> (_Z3addii);

float add(float,float)被重定义为----------->(_Z3addff);

我们先看新名字的后半部分,猜想add代表函数名,ii代表两个int参数,ff代表两个float参数,所以,不难猜出,后半部分是  函数名+参数类型缩写。

那么Z3代表什么呢?是否与函数返回值有关,但是,上面两个函数返回值一个为int,一个为float,两个为什么会相同呢?


我们再写几个函数做一下验证:

void print(int i)---------------->_Z5printi;

void print(char c)------------->_Z5printc;

char *print(char* c)---------->_Z5printPc;

从上我们可以看出Z+数字 与返回值有一定关系。但具体的与返回值的关系我们不再深究,这与编译器有关,在Windows下会得到不同的结果。但是命名规则相同 “返回值类型+函数名+参数”


同理Windows下:


相同的代码

int add(int ,int)---------------------->?add@@YAHHH@Z;

float add(int ,int)------------------->?add@@YAMMM@Z;

具体我们不再深究,道理都是相同的,这里我把在Windows下查看的方法告诉大家(我用的是VS2010)。





在Debug目录下找到 ".map" 文件打开即可。



编译器是如何调用匹配重载函数的呢?

这里有几个规则:

1、精确匹配:参数匹配而不做转换,或者只是做微不足道的转换,如数组名到指针、函数名到指向函数的指针、T到const T;

2、提升匹配:即整数提升(如bool 到 int、char到int、short 到int),float到double;

3、使用标准转换匹配:如int 到double、double到int、double到long double、Derived*到Base*、T*到void*、int到unsigned int;

4、使用用户自定义匹配

5、使用省略号匹配:类似printf中省略号参数


一般情况下,我们多用到精确匹配与提升匹配,看下面的例子。

#include<iostream>
using namespace std;
void print(int x)
{
 cout<<x<<endl;
}
void print(double x)
{
 cout<<x<<endl;
}
void print(char x)
{
 cout<<x<<endl;
}
void print(char *x)
{
 cout<<x<<endl;
}
int main()
{
  int a = 1;
  short b = 2;
  float c = 1.1;
  char d = 'a';
  char *str ="abc";
  print(a);//精确匹配,调用print(int)
  print(b);//提升匹配,调用print(int)
  print(c);//提升匹配,调用print(double)
  print(d);//精确匹配,调用print(char)
  print(str);// 精确匹配,调用print(char*)
  system("pause");
  return 0;
}

但是,当在定义相同功能重载函数时,函数不能过多也不能过少。不然会出现不必要的麻烦。

例如:

定义了两个函数

 void print(char x);
void print(long x);
int main()
{
 int i = 1;
print(i);//调用print(char )?,还是print(long)?
}
此时就会出现问题!!!!


关于编译器是如何选择重载函数,恕我才疏学浅,并没有深究,这里给大家一个链接,大牛实力讲解C++函数重载,希望能对大家有所帮助。

http://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值