前言

hello,大家好,今天我们来分享一些有关于C++的知识点——函数重载。
在C语言中,我们是不可以定义同名的函数的,如果函数同名,是会报错的。但是在C++中,我们可以定义相同函数名的函数了,称之为函数重载。了解重载对于学习C++接下来的内容具有重要意义。
相对于函数名在C语言中的专一,在C++中,它可谓是花里胡哨了起来,一个函数名可以对应多个函数,开始养鱼了呢。今天的文章,就让我们一起走进函数名的鱼塘。

1.重载的概念

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

1.重载——我迫不得已成为海王的原因

请设想一下,在一个程序中,调用的函数数量非常多的时候,给每一个函数命名就会成为一件头疼的事情,函数多是全局的,所以不能重名。你也许会说,这个问题可以根据我们之前介绍过的命名空间来解决啊,C++的名空间机制确实可以使这个问题得到解决,但是,对于一组概念相同,而处理对象不同的函数,如果可以使用相同的函数名来命名,是不是会简化编程呢?
比如这个例子,求绝对值函数:

int abs(int a);//求整数的绝对值
double abs(double a);//求浮点数的绝对值

在我们的生活中,我们也会在不同场景下采用同名操作,比如上车,坐出租车时候上的是出租车,骑小电驴的时候上的是电瓶车,(当然,还有一种上车只可意会,不可言传。我是正经人哈)。在上面求绝对值的例子中,同样是求绝对值,对于不同数据类型的求绝对值,如果我们都采用不同的函数名的话,岂不是太过于费力了吗?
其实,从声明信息中,参数类型已经足够描述所要求的参数性质,C++编译器也可以根据函数的参数类型、数量和排列顺序的差异来区分同名函数,这就是函数重载技术,相应的同名函数称为重载函数。
重载函数不仅在一定程度上化解了一部分的函数命名问题,更重要的是,他在编程逻辑上,更加贴近人类的思维。所以,函数名养鱼的原因,你get到了吗?

2.C++函数重载的条件

1.条件

C++虽然可以通过重载技术使用相同的函数名,但并不是在什么情况下都可以,函数重载除了要<mark>保障函数名相同</mark>外,还需要满足以下条件中的<mark>至少一个</mark>:
<mark>1.形参数量不同
2.形参类型不同
3.形参多类型顺序不同</mark>

我们来举例看一下:

void f(int a, int b, int c)
{
   

}
void f(int a, int b)
{
   

}
void f(double a, int b)
{
   

}
void f(int b, double a)
{
   

}

我们来分析一下:

2.注意

下面我们来思考这样两个问题:

1.相同类型参数改变顺序算重载吗?

void f(int a, int b)
{
   

}
void f(int b, int a)
{
   

}

我们注意,以上两个函数参数顺序看起来可是不同的哦。让我们来运行一下看看:

我们发现,编译器报错了。我们仔细观察发现,在这两个函数里,是相同类型的参数,尽管我们貌似交换了两个参数的顺序,但定义的变量只是一个名字而已,编译器是区分不开同是int型的参数,我们称之为a或称之为b有什么本质上的不同。当我们再回过头来看上面的第三条时,我们就会对它有新的理解:

2.编译器请问你能分开调用哪一个吗?

我们来看看这个程序:

#include<iostream>
using namespace std;
int f(int a, int b,int c=1)
{
   
	return (a + b+c);
}
int f(int a, int b)
{
   
	return (a + b);
}
int main()
{
   
	cout<<f(1, 2);
	return 0;
}

当我们运行起来,我们发现这个程序是不成功的。至于为什么不成功呢?我们来分析一下:
我们传递了两个参数,这种写法既满足缺省时的调用,也满足下面不缺省时的调用,于是编译器傻傻分不清,导致调用失败。这样虽然是重载,是符合语法的,但是是一个自己给自己挖的坑啊。

3.返回类型不同可以标志重载吗?

int f(int a, int b)
{
   
}
void f(int a, int b)
{
   
}

我们来看这两个函数,他们的参数完全相同,但是返回类型不同,这样的两个函数可以构成重载吗?
让我们来看看编译器怎么回答:
根据编译器的反应来看,返回类型不同是不构成重载的。至于为什么返回类型不同不能作为重载的标志,涉及到的知识很多,我们先不展开介绍。不过我们可以从这样一个角度来试着理解这个问题,如果返回类型可以用来判断重载的话,我们再调用函数的时候,编译器怎么判断它应该调用哪一个返回类型的函数?编译器又懵圈了。编译器会产生下图中的内心独白:

3.C++——我可以重载的底气

我们说C++是在C语言的基础上发展而来的,但是C语言是不支持重载技术的,但是C++却可以,这是为什么呢?我们一起来探讨一下:
首先,我们来分析一下编译器连接的过程:
1.预处理–>头文件展开+宏替换+去掉注释+条件编译
2.编译–>检查语法,生成汇编代码
3.汇编–>把汇编代码转换成二进制的机器码
4.链接–>链接到一起生成一个可执行程序
在编译过程中,所有的函数名都会被处理,会被修饰,也可以说是命名置换。以void A(int x,int y)为例,如果C++函数编译后名称为_A_int_int,则C语言编译后名称则为_A。也就是说,C++可以通过不同的参数类型,个数,和顺序来区分不同的函数。
大概原理就如我们上面所讲,下图是借鉴地别人的详细分析,大家可以看一下:

总结

好的,我们今天的分享就到这里了。这篇文章主要介绍了有关于C++重载的一些知识,希望对大家有所帮助。这篇文章的标题是《C++之重载:函数名的鱼塘》,之所以选择鱼塘这个比喻,是想将一个函数名可以对应多个函数说地更生动些,编程是一件很苦恼的事情,我希望我可以从中挖掘出更多与现实生活可以关联的快乐。最后,分享给大家一首诗,名字叫海王,哈哈哈,这是根据电影《海王》产生的灵感写的,这部电影是高二时和同学们一起在班里看的,此海王非彼海王哦:

   我想在海天相接的地方
   放牧一群羊
   就像去年冬天不忍到来的雪
   就像日日悠然的海浪

   我想在海天相接的地方
   做一个被世界遗忘的王
   就像我曾经拥有的叉戟
   千年来未曾沾染血光

   我想在海天相接的地方
   随着风偶尔歌唱
   这样沉睡在远方的灯塔
   以及静默在遥远的街巷
   都会在歌声里
   将同样的远方遗忘

   我就在一个海天相接的地方
   在虚无与幻梦中缓慢生长
   在你还不知道我的梦的时候
   我为你预备了一个愿望
   这个愿望关于爱与和平
   关于一个孩子
   他的故事  
   就在海天相接的地方