C++ 函数重载

引言

什么是函数重载

之前看到过这样一个段子:一个商场中保洁阿姨刚拖完地,为了防止顾客摔倒,于是写下了“小心地滑”。这时候以为老外走了过来,看见了这个警告,就非常小心翼翼地滑了过去。

在日常生活中,一个词有多重意思,根据不同的语境来判断对应的意思,这时该词就被重载

函数重载:是函数的一种特殊情况,C++中允许在同一作用域中声名几个功能类似的同名函数,这些函数的**形参列表(参数个数 或 类型 或 顺序)**必须不同,常用来处理实现功能类似数据类型不同的问题。

为什么要有函数重载

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

double Add(double a, double b)
{
	return a + b;
}

int main()
{
	Add(10, 20);
	Add(12.3, 23.4);
	return 0;
}

如果上述代码在C语言中就一定会出错,C语言不允许有名字相同的函数。

  • 如果没有函数重载,类型不同的数据相加,就必须定义函数名为Add_int Add_double,如果数据在多一点,就又要定义不同的名字,会比较麻烦
  • 在类中,构造函数必须与类名相同,如果没有函数重载,实现起来相当困难
  • 操作符重载,增加了操作符所能代表的含义,如 + 可以连接字符串

使用函数重载的注意事项(名字修饰)

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

short Add(int a, int b)
{
	return a + b;
}

int main()
{
	Add(10, 20);
	Add(12, 23);
	return 0;
}

这两个函数属于函数重载吗?
当我们一编译就会出错,无法重载仅按返回类型区分的函数。所以我们在概念中就没有返回值类型不同这一项。
C++ 函数重载

为什么返回值类型不同不属于函数重载?

首先,简单的理解,如果两个int类型的数相加,一个函数返回类型是int,另一个是short,那到底应该按哪个返回?编译器又不知道,就会存在矛盾。

然后,C++编译器既然能编译相同名字的函数而不产生冲突,说明编译器在编译过程中会对函数的名字按照一定的规则进行修饰。

名字修饰(Name Mangling)

在C/C++中,一个程序要运行起来,需要经过四个阶段:预处理、编译、汇编、链接

Name Mangling是一种在编译过程中,将函数,变量的名称重新改编的机制,简单的说,就是编译器为了区分各个函数,将函数通过某种算法,重新修饰为一个全局的唯一的名称。

那么,如何查看C、C++中的名字修饰?我们通过一个简单的方式,只给函数声明,而不给定义,编译器一定会报错

C语言名字修饰
#include <stdio.h>

int Add(int a, int b);

int Sub(int a, int b);

int main()
{
	Add(10, 20);
	Sub(10, 20);
	return 0;
}

一编译就会报错:C++ 函数重载

由上图可以看出,我们给了两个名字不同的函数,编译器报错:找不到 _Add _Sub
说明C语言中,只是简单的在函数名字前面加上下划线,并没有过多的修饰,所以在C语言中不支持函数重载。

C++名字修饰
#include <iostream>
using namespace std;

int Add(int a, int b);

double Add(double a, double b);

double Add(int a, double b);

int main()
{
	Add(10, 20);
	Add(12.3, 23.4);
	Add(10, 12.3);
	return 0;
}

给了三个不同类型的形参,一经编译报错:
C++ 函数重载

这下我们就能看到C++中函数名字修饰和C语言有很大的不同。C++编译器在编译时将函数名字修饰陈一个比较复杂的名字,被修饰后的名字中包含:函数名字以及参数类型,这也就是为什么C++中名字相同,参数类型不同的函数仍然可以通过编译而不出错。

接下来我们分析一下每一块表示的含义:
C++ 函数重载

总结

  • main函数不能重载(因为程序只能有一个入口)
  • 函数重载必须在同一作用域
  • 返回值类型不同,参数列表完全相同不属于函数重载
  • 函数重载的形参列表 参数个数 或 类型 或 顺序 必须不同