重载的奥义之函数重载

一、基本定义        

        重载,顾名思义从字面上理解就是重复装载,打一个不恰当的比方,你可以用一个篮子装蔬菜,也可以装水果或者其它,使用的是同一个篮子,但是可以用篮子重复装载的东西不一样。

        函数重载是C++多态(静态多态)的特征体现,它可以允许重复使用同一个函数名(篮子)的函数,但是函数的参数列表(篮子装的东西)是可以不一样的。这样就可以利用函数的重载功能设计一系列功能相近,但是功能细节不一样的函数接口。


二、应用举例        

        以同一个函数printData为例:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void printData(const char *str, int num)
 5 {
 6   //函数体;
 7 }
 8 
 9 void printData(const char *str)
10 {
11   //函数体;
12 }
13 
14 void printData(double data, int num)
15 {
16   //函数体;
17 }
18 
19 void printData(int data, int num)
20 {
21   //函数体;
22 }
23 
24 void printData(long data, char num)
25 {
26   //函数体;
27 }
28 
29 class Test
30 {
31   public:
32          void MyPrint(int num) {cout << "class int: " << num << endl;}
33          void MyPrint(float num) {cout << "class float: " << num << endl;}
34          void MyPrint(char num) {cout << "class char: " << num << endl;}
35 };
36 
37 int main(void)
38 {
39   printData("hello", 5); // (const char *str, int num)
40   printData("hello"); // (const char *str)
41   printData(1993.0, 97);
42   printData(1993, 98);
43   printData(1993L, 99);
44   Test test1;
45   test1.MyPrint(2); // class int: 2
46   test1.MyPrint(2.0f); // class float: 2.0 浮点型必须要显式类型,否则编译器不知道该转换为int还是float。
47   test1.MyPrint("hello"); // class char: hello
48   return 0;
49 }

  使用重载函数时,需要在函数调用中使用与对应的重载函数匹配的函数参数类型。

        而如下:

1 unsigned int para = 4321;
2 printData(4321, 5);

        此时的printData调用和哪个原型匹配呢?答案它不与任何函数原型匹配,而没有匹配的原型不会停止调用其中某一个函数,C++会尝试用标准的强制类型转换与之匹配,比如使用 printData(double data, int num),就可以将para的类型强制转换为double类型。但是还有printData(int data, int num)和printData(long data, char num)这两个函数可以强制转换para。因此,C++将拒绝这种函数的调用,将这种调用视为错误。

        重载函数通常用在同一个作用域内,用同一个函数名命名一组功能相似的函数,这样做减少了函数名的数量,提高了函数的通用性,避免了名字空间的污染,对于程序的可读性有很大的好处。


三、非函数重载的情况

        下面这种两种情况不能视为函数重载:

1 int fun(int a);
2 int fun(int &a);

        从编译器的角度出发,参数a与参数列表原型int a和int &a都匹配,编译器无法确定使用哪个函数,为避免这种混乱,编译器在检查参数类型时将把类型本身和类型引用看作是同一个特征类型。

1 int fun(int a, float b);
2 double fun(int a, float b);

        C++不允许这样的方式重载函数,虽然返回值可以不一样,但是参数列表必须不一样。


四、函数重载的使用原则

        (1)、仅当函数的基本功能比较相近,但是需要使用不同形式的参数实现功能时才应该使用函数重载,尽量不要用同一函数名去实现完全不相干的功能;

        (2)、在同一个作用范围内使用函数重载,同一个范围即:同一个命名空间或者同一个类等;

        (3)、重载函数的名称必须相同,函数的参数列表须不相同,即参数列表中参数的类型,参数的个数或参数的顺序不相同;

        (4)、重载函数可以有相同的返回值类型或者不同的返回值类型,反之仅仅是返回类型不同不足以作为函数的重载。


五、FAQ

1、C++中对函数重载是如何处理的?

        在.cpp文件中,虽然两个函数的函数名一样,但是,C++编译器在内部使用“名称修饰”或“名称矫正”转换,它根据函数中参数列表的区别为每个函数进行加密 ,例如:

        int fun(int a, float b)和double fun(int a, float b)

        编译器在内部可以转换为:

        ?fun@@YAHHH@Z和?fun@@YAMMM@Z

         "?"表示名称开始,"?"后边是函数名;“@@YA”表示参数表开始,后边的3个字符分别表示返回值类型,两个参数类型;“@Z”表示名称结束。

        由于在.cpp文件中,两个函数生成的符号表中字符的名称不一样,所以是可以编译通过的。

2、C语言中为什么不能支持函数重载?

        编译器在编译.c文件时,只会给函数进行简单的重命名。具体的方法是给函数名之前加上"_”;所以编译前两个函数名相同的函数在编译之后的函数名也照样相同;因此调用时会因为不知道到底调用哪个而出错。

        int fun(int a, float b)和double fun(int a, float b)

        编译器在内部都转换为:_fun,无法区分,

        只有不同的函数名字int fun1(int a, float b)和double fun2(int a, float b)

        编译器在内部转换为:_fun1和_fun2,这才能区分开来。


 更多技术内容和书籍资料获取敬请关注微信公众号“明解嵌入式”

posted @ 2023-01-08 09:58  Sharemaker  阅读(225)  评论(0编辑  收藏  举报