目录

🍯1.4 函数重载
🥝1.函数重载的定义
C语言不支持函数重载
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。同名函数要求函数名相同,但参数不同:1、参数类型不同
1
int Add(int left, int right) //函数名同为Add,函数参数为int型 { return left + right; } double Add(double left, double right) //函数名同为Add,但参数为double型 { return left + right; } int main() { cout << Add(2, 3) << endl; //传入的参数都为int型,默认使用第一个Add函数 cout << Add(2.5, 3.4) << endl; //传入的参数为浮点型,使用第二个Add函数 }
2、参数个数不同
void print() //没有传入参数时,使用该print函数 { cout << "NULL" << endl; } void print(int a) //传入参数时,使用该print函数 { cout << a << endl; } int main() { print(); print(20); }
3、形参类型顺序不同
1
void f(int a, char b) //int型参数在前 { cout << "f(int a,char b)" << endl; } void f(char b, int a) //char型参数在前 { cout << "f(char b, int a)" << endl; } int main() { f(10, 'a'); //整型在前,字符型在后,因此使用第一个f函数 f('a', 10); }
1
Q1:使用函数重载的好处是什么?
A1:我们在这里可以与C语言进行比较,比如说我们要交换两个int型与double型的数值,就会写两个swap函数,如果我们使用C语言的话,其代码操作如下:
void swap_int(int* a, int* b) //交换整型值的函数,取名为swap_int { int tmp = *a; *a = *b; *b = tmp; } void swap_double(double* a, double* b) //交换double型值的函数,取名为swap_double { double tmp = *a; *a = *b; *b = tmp; } int main() { int x = 10, y = 20; double m = 3.14, n = 2.69; swap_int(&x, &y); //交换x与y的值 swap_double(&m, &n); //交换m与n的值 }由于C语言不支持同名函数,因此在交换int型值与double型值的swap函数代码逻辑虽然类似,但是函数名不能相同,但如果是使用C++,就可以使用同名函数+不同参数类型,虽然代码依然重复,但是使用时会非常爽,看起来像用同一个函数一样,在某种程度上减轻了程序员起名字、记名字的负担。
void swap(int* a, int* b) //取名为swap { int tmp = *a; *a = *b; *b = tmp; } void swap(double* a, double* b) //都可以取名为swap { double tmp = *a; *a = *b; *b = tmp; } int main() { int x = 10, y = 20; double m = 3.14, n = 2.69; swap(&x, &y); swap(&m, &n); }Q2:下面这两个函数属于函数重载吗?
short Add(int x, int y) { return x + y; } int Add(int x, int y) { return x + y; }A2:不属于,这两个函数仅仅是函数的返回值类型不同,形参的类型、个数与顺序都是相同的,计算机将无法根据传入的参数区分调用的是哪个函数。
🥝2. 如何实现函数重载
编译链接的过程:预处理——>编译——>汇编——>链接
- 预处理:头文件展开、宏替换、条件编译、去掉注释——>生成 test.i
- 编译:检查语法、生成汇编代码(有语法错误就会在这一步跳出)——>生成test.s
- 汇编:把汇编代码转换成二进制的机器码(0/1序列)——>生成test.o
- 链接:找调用函数的地址,链接对应上,合并到一起(有函数声明,没有函数定义时,就会报链接错误)。
Q1:为什么C++支持函数重载,而C语言不支持函数重载呢?
A1:这是因为使用gcc编译编译后函数的名字不会发生改变;而g++编译后函数名就会变成【Z+函数长度+函数名+类型首字母】的组合,这就使得计算机在进行链接操作时可以通过具体形参的不同从而在多个相同名字的函数中选出正确的那个函数。我们可以通过一个来进行对比。
int Add(int a, int b) { return a + b; } float Add(float a,float b) { return a + b; }
- 使用C语言编译器编译:对上述代码使用C语言进行编译,实际过程中我们只能编译一个Add函数,会发生报错;通过下面的结果我们得知,在Linux下,采用gcc编译完成后,函数名字的修饰没有发生任何改变。
00000000004004ed: /*这里的函数名为Add*/ 4004ed: 55 push %rbp 4004ee: 48 89 e5 mov %rsp , %rbp 4004f1: 89 7d fc mov %edi, -0x4(%rbp) 4004f4: 89 75 f8 mov %esi, -0x8( %rbp) 4004f7: 8b 45 f8 mov -0x8( %rbp) , %eax 4004fa: 8b 55 fc mov -0x4(%rbp ) ,%edx 4004fd: 01 d0 add %edx , %eax 4004ff: 5d pop %rbp 400500: c3 retq- 使用C++编译器编译:对上述的两个Add函数都可以进行编译;通过下面的结果我们得知,在Linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数的类型信息也添加到修改后的名字中。
00000000004004ed<_Z3Addii>: /*Add后面的ii是形参类型int int的首字母简写*/ 4004ed: 55 push %rbp 4004ee: 48 89 e5 mov %rsp , %rbp 4004f1: 89 7d fc mov %edi, -0x4(%rbp) 4004f4: 89 75 f8 mov %esi, -0x8( %rbp) 4004f7: 8b 45 f8 mov -0x8( %rbp) , %eax 4004fa: 8b 55 fc mov -0x4(%rbp ) ,%edx 4004fd: 01 d0 add %edx , %eax 4004ff: 5d pop %rbp 400500: c3 retq 00000000004005c1<_Z3Addff>: /*Add后面的dd是形参类型float float的首字母简写*/ 4004ed: 55 push %rbp 4004ee: 48 89 e5 mov %rsp , %rbp 4004f1: 89 7d fc mov %edi, -0x4(%rbp) 4004f4: 89 75 f8 mov %esi, -0x8( %rbp) 4004f7: 8b 45 f8 mov -0x8( %rbp) , %eax 4004fa: 8b 55 fc mov -0x4(%rbp ) ,%edx 4004fd: 01 d0 add %edx , %eax 4004ff: 5d pop %rbp 400500: c3 retq