码迷,mamicode.com
首页 > 其他好文 > 详细

函数重载

时间:2016-06-27 21:53:59      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

1、什么是函数重载???
 在同一个作用域中,如果有多个函数的名字相同,但是形参列表不同(参数类型不同或参数个数不同),返回值类型可同也可不同,我们称之为重载函数。重载的函数是通过形参列表区分的,与返回值类型无关。函数重载其实是"一个名字,多种用法"的思想,不仅函数可以重载,运算符也可以重载。
例如:现在要实现一个加法运算,运算子可以是整形也可以是浮点型,就可以通过重载实现。
int ADD(int a, int b)
{
        return a + b;
}

float ADD(float a, int b)
{
        return a + b;
}

float ADD(int a, float b)
{
        return a + b;
}

float ADD(float a,float b)
{
                 return a + b;
}

  这样实现后,我们要进行加法运算,则只需要调用ADD函数,编译器会根据我们传递实参的类型和个数推断出想要调用哪个ADD函数。

注意:main函数不能重载,因为程序的入口只能有一个。


2、为什么要有重载???
  假如我们在C中要定义一个打印print函数,它可以输出整型,字符型,字符串。虽然这些函数的功能类似,但是我们必须将他们声明成不同的名字让编译器进行区分,比如:
   void print_int(int a);
   void print_char(char c);
   void print_string(char *str);
而在C++中我们可以利用函数重载以便于将这些函数的名字统一起来:
   void print(int a);
   void print(char c);
   void print(char *str);

  函数的名字仅仅是让编译器直到它调用的是哪个函数,用户并不关心函数的名字。而函数重载可以再一定程度上减轻程序员起名字,记名字的负担。



3、c和c++中对函数重命名的区别? 在c++程序中可以引入c代码,但前提是要在前面加上 extern "C" 这样的字样,这又是为什么呢?

  在程序进行编译期间,编译器会对函数进行重命名,因为c++中有重载的概念,所以编译器在对c和c++中的函数进行重命名时的规则一定不同,下面我们来看看有何不同。

  首先在属性页中确定生成映射文件(是软件编译后产生的有关用到的所有程序,数据及IO空间的一种映射文件)。编译之后会在项目中的Debug文件中会生成.map文件,打开就可以看到编译器为函数进行的重命名。
技术分享

技术分享

   下面这幅图中是编译器对c程序中函数的重命名。可以看到编译器对ADD函数的重命名结果是
_ADD,这也很好的解释了c中的函数名为什么不能相同,否则会发现重定义的情况。
技术分享
技术分享


  下面这幅图是编译器对c++程序的重命名,我们可以看到,虽然有4个名字都为ADD的函数,但是经过编译器重命名之后,这四个名字各不相同。
技术分享

技术分享



   在c++中,编译器无法识别c规则下的函数重命名,所以在c++中使用c代码要使用 extern "C" 这样的字样,告诉编译器,这个代码是c规则的重命名。


4、编译器如何解决重载时的命名冲突???
windows系统下:
技术分享


  既然我们知道重载函数是是根据形参列表进行区分的,一个函数声明由 返回值+函数名+参数列表 构成,那么我们可以做一个假设:
?ADD@@YAHHH@Z    ?代表开始 ADD是函数名,@@YA代表参数开始  第一个H代表返回值类型int 剩下的代表参数int int.


5、编译器如何解析重载函数调用?
  一组重载函数有多个,我们需要以合理的实参调用它们。编译器首先将调用的实参与重载集合中每一个函数的形参进行比较,然后根据比较结果确定要调用哪个函数。
函数匹配(重载确定):把函数调用与我们要调用的函数关联起来,注意这时候已经确定我们要调用这组函数中的哪一个了。

当调用重载函数时有三种情况:
1、编译器找到一个与实参最佳匹配的函数,并调用这个函数。
例如: ADD(2,3)调用的就是int ADD(int,int).
2、找不到任何一个函数的参数与调用的实参匹配,此时编译器会发出无法匹配的错误。
例如: ADD("abc","def") 就是错误的。
3、有多于一个函数可以匹配,但是每一个都不是明显的最佳选择,此时回发生错误。(二义性调用)
例如:
int ADD(int,int);
int ADD(flaot,int);
ADD(3.6f,3.1f)就是二义性调用。

调用匹配:
      精确匹配,参数匹配不做转化,例如ADD(2,3)调用的是int ADD(int,int).
      提升匹配:即整数提升,例如ADD(2.3,3.2)调用int ADD(int,int)。2.3和3.2都提升成int型。



6、重载与作用域?

例:
void print(double );
void print(char *);

void fun()
{
      void print(int );          //新作用域,隐藏了之前的print
      print( "hello world" );     //错误 print(char *)被隐藏了
      print(6.66);              //正确 调用的是print(int);  print(double)被隐藏了
}

  当调用print函数时,编译器首先寻找对该函数的声明,找到的是接受int值的那个局部声明,一但在当前作用域中找到了所需要的名字,编译会忽略掉外层作用域中的同名实体。之后就是检查函数调用是否有效。所以,一般将函数的声明都置于全局作用域中。

下面这种就能够正确的调用:
void print(double );
void print(char *);
void print(int );

void fun()
{
                print( "hello world");   
                print(6.66);            
}

函数重载

标签:

原文地址:http://blog.csdn.net/lf_2016/article/details/51769789

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!