2. 函数重载

在 C 语言中,同一个 .c 文件中不可以用同名的函数或变量,否则会出现标识符冲突的错误。如果在不同的 .c 文件中有同名的函数存在,也需要使用 static 将多个函数修饰为静态函数,最多保留一个同名的非静态函数。但在 C++ 中则可以允许函数名相同,但函数名的形参个数或者形参类型不同的同名函数存在。

什么是函数重载:

函数重载(function overload)是指C++在一个应用程序内允许有相同的函数名称,但参数列表的个数和类型不同的函数定义(对返回值类型没有要求,不根据返回值进行区别)。

函数调用时会根据实际参数的类型和个数自动匹配相应函数。

区别:

示例:

// filename: func_overload.cpp
#include <iostream>

using namespace std;

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

float myadd(float x, float y, float z) {
    return x + y + z;
}

int main(int argc, char * argv[]) {
    cout << myadd(1, 2) << endl;
    cout << myadd(3.4, 5.6, 7.8) << endl;

    return 0;
}

编译和运行结果如下:

weimz@mzstudio:~$ g++ -o func_overload func_overload.cpp
weimz@mzstudio:~$ ./func_overload 
3
16.8

根据运行结果可以看出,表达式 myadd(1, 2) 调用的函数是 int myadd(int a, int b),而 表达式 myadd(3.4, 5.6, 7.8) 则调用的函数是 float myadd(float x, float y, float z)

实现原理

C 语言的函数在经过编译阶段他的函数名不会改变,如 C 语言的函数 int myadd(int a, int b) 的函数名就一定是 myadd 在链接阶段也会根据函数名来匹配对应的函数,则 static 修饰后的函数则在编译阶则会隐藏此函数名为不可见。但在 C++ 语言中 任何的函数都会根据函数名和形参的类型在编译阶段重新定义函数名,在调用函数的地方编译器会根据实际参数来匹配对应的函数。

例如在编译后的目标文件中,可以使用 GCC 的 nm 命令查看函数的真实名字。 如下所示。

重载是编译器将函数名根据参数类型添加名称前缀和后缀来实现的。

以下是上述示例编译后的目标文件中的真实的函数名。

weimz@mzstudio:~$ gcc -o func_overload.o -c func_overload.cpp
weimz@mzstudio:~$ nm func_overload.o
                 U _GLOBAL_OFFSET_TABLE_
0000000000000040 T main
0000000000000018 T _Z5myaddfff
0000000000000000 T _Z5myaddii
                 U _ZNSolsEf
                 U _ZNSolsEi
                 U _ZNSolsEPFRSoS_E
                 U _ZSt21ios_base_library_initv
                 U _ZSt4cout
                 U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_

其中字母 T 表示后面的名称是一个函数名(标签)。可见函数 int myadd(int a, int b) 编译后的函数名 _Z5myaddii, 而函数 float myadd(float x, float y, float z) 编译后的函数名为 _Z5myaddfff,而 main 函数的函数名依旧是 main 不变。

其中 _Z5myaddii 后面的 ii 表示两个整数型参数,_Z5myaddfff 后面的 fff 表示三个浮点数参数。

实验

自己尝试使用运算符重载定义函数名相同,参数不同并有缺省参数的多个函数,并尝试调用这些函数。