函数重载要求编译器能够唯一地确定调用一个函数时应执行哪个函数代码,即采用哪个函数实现。确定函数实现时,要求从函数参数的个数和类型上来区分。这就是说,进行函数重载时,要求同名函数在参数个数上不同,或者参数类型上不同。否则,将无法实现重载。
参数类型上不同的重载函数
下面举一个在参数类型不同的重载函数的例子:
#include <iostream.h>
int add(int, int)
double add(double, double)
void main()
{
cout<<add(5, 10)<<endl
cout<<add(5.0, 10.5)endl
}
int add(int x, int y)
{
return x+y
}
double add(double a, double b)
{
return a+b
}
该程序中,main()函数中调用相同名字add的两个函数,前边一个add()函数对应的是两个int型数求和的函数实现,而后边一个add()函数对应的是两个double型数求和的函数实现。这便是函数的重载。
以上程序输出结果为:
15
15.5
参数个数上不同的重载函数
下面举一个在参数个数上不相同的重载函数的例子:
#include <iostream.h>
int min(int a, int b)
int min(int a, int b, int c)
int min(int a, int b, int c, int d)
void main()
{
cout<<min(13, 5, 4, 9)<<endl
cout<<min(-2, 8, 0)<<endl
}
int min(int a, int b)
{
return a<b?a:b
}
int min(int a, int b, int c)
{
int t = min(a, b)
return min(t,c)
}
int min(int a, int b, int c, int d)
{
int t1 = min(a, b)
int t2 = min(c, d)
return min(t1, t2)
}
该程序中出现了函数重载,函数名min对应有三个不同的实现,函数的区分依据参数个数不同,这里的三个函数实现中,参数个数分别为2,3和4,在调用函数时根据实参的个数来选取不同的函数实现。
首先明确重载函数的定义:在相同的声明域中的函数名相同的,而参数表不同的,即通过函数的参数表而唯一标识并且来区分函数的一种特殊的函数。当将要定义一组函数,使它们执行一系列的 *** 作,但是它们是应用在不同的参数类型上的。此时可以选择重载函数。
对于函数的用户来说,他们并不关心函数定义的细节,也就是说他们不关心判断两个整数的大小和判断数组(vector容器)数的大小应该使用不同的函数,而对于程序的设计者来说这可是不得不想到的。程序员必须记住并查找每个函数名。而函数的重载把程序员从这种问题的复杂性中解放了出来,C++提供了这种支持。
函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数。重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于程序的可读性有很大的好处。
1.2、为什么需要函数重载(why)? 试想如果没有函数重载机制,如在C中,你必须要这样去做:为这个print函数取不同的名字,如print_int、print_string。这里还只是两个的情况,如果是很多个的话,就需要为实现同一个功能的函数取很多个名字,如加入打印long型、char*、各种类型的数组等等。这样做很不友好! 类的构造函数跟类名相同,也就是说:构造函数都同名。如果没有函数重载机制,要想实例化不同的对象,那是相当的麻烦!*** 作符重载,本质上就是函数重载,它大大丰富了已有 *** 作符的含义,方便使用,如+可用于连接字符串等!
我们在开瓶瓶罐罐的时候,经常会遭遇因各种瓶口规格不同而找不到合适的工具的尴尬。所以有时候就为了开个瓶,家里要备多种规格的开瓶器。同样是开个瓶子嘛,何必这么麻烦?于是有人发明了多功能开瓶器,不管啤酒瓶汽水瓶还是软木塞的红酒瓶都能轻松打开。
然而开瓶器的问题也会发生到程序设计中。比如我们要编写一个函数来求一个数的绝对值,然而整数、浮点型数、双精度型数都有绝对值,但为它们编写的函数返回值类型却是各不相同的。比如:
int iabs(int a)
float fabs(float a)
double dabs(double a)
这样是不是有点备了多种开瓶器的感觉?我们能不能在程序设计中也做一个多功能的开瓶器,把所有数据类型的求绝对值都交给abs这一个函数呢?
在C++中,我们也能够把具有相同功能的函数整合到一个函数上,而不必去写好多个函数名不同的函数,这叫做函数的重(音chóng)载(Overload)。重载的本质是多个函数共用同一个函数名。
我们先来看一个函数重载的实例:(程序6.3)
#include "iostream.h"
int abs(int a)//当参数为整型数据时的函数原型
float abs(float a)//当参数为浮点型数据时的函数原型
double abs(double a)//当参数为双精度型数据时的函数原型
int main()
{
int a=-5,b=3
float c=-2.4f,d=8.4f
double e=-3e-9,f=3e6
cout <<"a=" <<abs(a) <<endl <<"b=" <<abs(b) <<endl//输出函数返回的结果
cout <<"c=" <<abs(c) <<endl <<"d=" <<abs(d) <<endl
cout <<"e=" <<abs(e) <<endl <<"f=" <<abs(f) <<endl
return 0
}
int abs(int a)//函数定义
{
cout <<"int abs" <<endl//显示运行了哪个函数
return (a>=0?a:-a)//如果a大于等于零则返回a,否则返回-a。
}
float abs(float a)
{
cout <<"float abs" <<endl
return (a>=0?a:-a)
}
double abs(double a)
{
cout <<"double abs" <<endl
return (a>=0?a:-a)
}
运行结果:
int abs
int abs
a=5
b=3
float abs
float abs
c=2.4
d=8.4
double abs
double abs
e=3e-009
f=3e+006
运行结果表明,abs函数果然能够处理三种不同数据类型的数据了。那么我们怎样才能自己造一个“多功能工具”呢?
其实要编写一个重载函数并不是很麻烦。首先,我们要告诉电脑,同一个函数名存在了多种定义,所以,我们要给同一个函数名写上多种函数原型(如程序6.3的第二到第四行);其次,我们要对应这些函数原型,分别写上这些函数的定义(如程序6.3的主函数体之后,对三个abs函数的定义)。
然而电脑又是如何来识别这些使用在不同环境下的“工具”的呢?
在日常生活中使用到多功能工具,如果我们不知道具体应该使用哪个工具,我们会把每个工具放上去试一试,如果只有唯一一个工具适合,那么我们就毫无疑问地能够确定就是使用它了。但是如果出现了两个或者两个以上工具都能适合,我们就分不清到底应该使用哪个是正确的了。
电脑的做法和我们是类似的。电脑是依靠函数声明时参数表中参数个数、各参数的数据类型和顺序来判断到底要运行哪个函数的。因此,当重载函数参数表完全相同的时候,电脑便无法判断应该运行哪个函数,于是程序就出错了。
我们了解了电脑是如何识别重载函数以后,发现要编写一个重载函数还是需要注意一些地方的,那就是:在重载函数中,任意两个函数的参数表中的参数个数、各参数的数据类型和顺序不能完全一样。例如int func(int a,char b)和float func(int c,char d)就不能重载,因为它们的参数个数、各参数的类型和顺序完全一样,即使形参名不同、返回值类型不同也是无济于事的。
在调用一个重载函数时,可能会发生找不到一个完全合适的函数。这时候,就需要进行数据类型的转换。由于这种方法可能导致数据丢失或数据类型不严格符合,且在充分考虑问题后,这种情况是可以尽量避免的,所以这里不再就这个问题展开论述。有兴趣的读者可以查阅其他C++的参考资料。
算法时间:重载函数
从某种意义上说,重载函数是方便了函数的使用者。在前一节我们知道,如果完成了所有函数的编写,那么完成一个程序就像搭积木一样简单了。然而如果功能相似名字却不同的函数太多,那么多“积木”搭起来也未必简单。当函数的编写者充分考虑了不同情况下应该运行稍有不同的函数,函数的使用者就不必为这些小细节而烦恼了。不过重载函数的函数名还是应该符合其功能,如果把功能完全不同的函数重载,那么就大大影响了程序的可读性。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)