8.9 - 函数重载
Key Takeaway
- 使用相同函数名但形参不同的函数,称为函数重载。
- 只要编译器能够区分每个重载函数,函数就可以被重载。如果不能区分重载函数,将导致编译错误。
- C++ 中的操作符其实也是函数,所以它们也可以被重载
- 重载函数能够进行编译,必须满足两个条件:
- 每个重载的函数都必须能够区分。我们会在 8.10 - 函数重载和区分 中介绍它们是如何被区分的。
- 每个被调用的重载函数在重载解析时必须能够定位到一个函数。我们会在8.11 - 函数重载解析和匹配歧义中介绍如何进行重载函
考虑下面的函数:
1 2 3 4 |
|
这个简单的函数将两个整数相加并返回一个整数结果。但是,如果我们还需要一个可以将两个浮点数相加的函数呢?这个 add()
函数并不能实现浮点数相加,因为任何浮点形参都会被转换为整数,导致浮点形参丢失它们的小数值。
解决这个问题的一种方法是定义多个名称略有不同的函数:
1 2 3 4 5 6 7 8 9 |
|
但是,为了达到最佳效果,你必须为具有不同类型参数的类似函数,定义一致的命名标准,同时记住这些函数的名称,并确保使用正确的函数。
将来,如果我们又需要一个类似的函数,将三个整数相加而不是两个整数相加的时候会发生什么?为每一个函数创建不同的名称会使代码变得难以维护。
函数重载简介
幸运的是,C++ 提供了一个优雅的解决方案。函数重载允许我们使用相同的名称创建多个函数,只要每个相同名称的函数具有不同的形参类型(或者可以用其他方式区分函数)。每个函数都共享一个名称(在同一个作用域中),称为重载(overload)函数(有时简称重载)。
对 add()
函数进行重载,我们可以声明另外一个add()
函数,但是参数类型为double
:
1 2 3 4 |
|
此时,在同一个作用域中,出现了两个同名的 add()
函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
以上程序是可以编译的。尽管你可能担心这些函数会出现命名冲突,但实际上并不会。因为这些函数的形参类型不同,所以编译器能够区分这些函数,并将它们视为共享一个名称的单独函数。
关键信息
只要编译器能够区分每个重载函数,函数就可以被重载。如果不能区分重载函数,将导致编译错误。
相关内容
因为 C++ 中的操作符其实也是函数,所以它们也可以被重载,我们会在 14.1 -- Introduction to operator overloading中进行介绍。
函数重载解析
此外,当调用被重载的函数时,编译器会基于形参来匹配最合适的函数调用——称为重载解析(overload resolution)。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
上述函数编译执行的结果如下:
1 2 |
|
当提供整型形参时(add(1, 2)
)编译器可以判断出我们需要调用的是 add(int, int)
。而当我们提供浮点类型的形参时( add(1.2, 3.4)
),编译器能够确定我们调用的是add(double, double)
。
使重载的函数能够编译
为了使使用了重载函数的程序能够进行编译,必须满足两个条件:
- 每个重载的函数都必须能够区分。我们会在 8.10 - 函数重载和区分 中介绍它们是如何被区分的。
- 每个被调用的重载函数在重载解析时必须能够定位到一个函数。我们会在8.11 - 函数重载解析和匹配歧义中介绍如何进行重载函数的匹配。
如果重载函数不能被区分,或者重载函数的函数调用无法解析为重载函数,则将导致编译错误。
在下一课中,我们将探讨如何区分重载函数。然后,在再下一课中,我们将探索编译器如何将函数调用解析为重载函数。
小结
函数重载通过减少需要记住的函数名的数量来降低程序的复杂性。它可以而且应该被广泛使用。
最佳实践
使用函数重载可以简化程序。