hello,everyone,鸡啄米上一节讲到的是函数的参数传递和内联函数,这一讲鸡啄米会给大家讲点稍微有点难度的函数重载和函数模板,如果大家把之前的编程入门课程都掌握了,这一讲的内容自己上机试下就很容易理解了。
一.重载函数
现实生活中的一个词可能有多种含义,比如,洗衣服、洗头、洗车,都有一个洗字,但是他们的操作方式是不一样的。函数也一样,有时候它们的操作不完全一样但是名字一样,这就是重载函数。
重载函数就是,两个以上的函数取相同的函数名,但是函数形参的个数或者类型不同,编译器会根据实参与形参的类型和个数进行最佳匹配,自动确定调用哪一个函数。
为什么要有重载函数呢?因为如果没有重载函数,那么对不同类型的数据进行类似的操作也要定义不同名称的函数,比如加法函数,就必须对整数加法和浮点数加法分别定义不同的函数名:
int nadd(int a, int b); float fadd(float a, float b);
这样调用需要记住的函数名太多,而且功能类似,很不方便。鸡啄米给大家举几个重载函数的例子:
形参类型不同的例子:
int add(int x,int y); float add(float x,float y);
形参个数不同的例子:
int add(int x,int y); int add(int x,int y,int z);
鸡啄米在这里要提醒几个需要注意的地方:
1.重载函数的形参不管是类型还是个数必须有一样是不同的。因为编译器就是看实参和哪个函数的形参的类型及个数匹配,来判断调用哪个函数,如果函数名、形参类型和个数相同,即使函数返回值类型不同,编译器也会认为是函数重复定义的语法错误,就是说它认为是一个函数。以下两种是错误的重载函数:
int add(int x,int y); int add(int a,int b);
上面两个函数虽然形参名不同,但是编译器不会以形参名来区分函数,它会认为这是一个函数。我们以后也要记住,若只改变形参名则函数不会变,调用的地方也不必变。
int add(int x,int y); void add(int x,int y);
上面这两个函数返回值不同,确实是两个函数,但是编译器也不会以返回值来区分函数,也会认为是重复定义。
2.重载函数都是进行类似的操作,不要把不同的功能定义成重载函数,否则会让人对调用有误解,比如:
int add(int x,int y) { return x+y; } float add(float x,float y) { return x-y; }
这两个函数一个是实现的两个数的加法,一个是实现减法,在语法上并没有问题。但是功能不一样但是都叫add,我们调用的时候是不是会混淆?
鸡啄米给大家一个重载函数的例子,大家仔细研究下代码,上机试下,通过上面的讲解,很容易理解:
#include <iostream> using namespace std; int add(int m,int n); // 函数调用前必须先声明函数原型 float add(float x,float y); int _tmain(int argc, _TCHAR* argv[]) { int m, n; float x, y; cout<<"Enter two integer: "; cin>>m>>n; cout<<"integer "<<m<<'+'<<n<<"="<<add(m,n)<<endl; cout<<"Enter two float: "; cin>>x>>y; cout<<"float "<<x<<'+'<<y<<"= "<<add(x,y)<<endl; return 0; } int add(int m,int n) { return m+n; } float add(float x,float y) { return x+y; }
屏幕先输出Enter two integer:,我们输入2 3,则屏幕会接着显示integer 2+3=5,然后继续提示Enter two float:,我们继续输入2.1 3.4,最后屏幕会出现float 2.1+3.4=5.5。
二.函数模板
有时候我们使用重载函数还不能达到最优的效果,比如,两个求绝对值的函数:
int abs(int x) { return x<0 ? -x:x; } double abs(double x) { return x<0 ? -x:x; }
大家观察下这两个函数,这两个函数只是返回值类型和参数类型不同,功能完全一样,如果能有办法写一段通用的代码适用于多种不同的数据类型,就是不用像上面那样写两个函数而只是一段代码就能实现两个函数的功能,那代码的复用性不是更高了吗?开发效率也会提高的。这就要函数模板来实现了。
模板是有可以使用和操作任何数据类型的通用代码构成,这种程序设计叫做参数化程序设计,因为它把数据类型当成了参数,可以用来创建一个通用功能的函数,支持多种不同类型的形参和返回值。函数模板的定义形式是:
template
< typename 标识符>
函数定义
鸡啄米给大家一个上面那样求绝对值的函数模板示例:
#include <iostream> using namespace std; template T abs(T x) { return x<0 ? -x:x; } int _tmain(int argc, _TCHAR* argv[]) { int n = 5; double d = -2.3; cout << abs(n) << endl; cout << abs(d) << endl; return 0; }
鸡啄米给大家分析下这个程序,编译器会根据调用abs函数时传入实参的类型来确定函数模板的类型参数是什么类型。上面使用调用表达式abs(n)时,因为n是int类型,所以模板中类型参数T就是int,然后编译器会以函数模板为样板生成一个函数:
int abs(int x) { return x<0 ? -x:x; }
同样,对于调用表达式abs(d),因为d是double类型,所以类型参数T就是double,编译器会根据函数模板生成下面的函数:
double abs(double x) { return x<0 ? -x:x; }
所以,abs(n)实际上调用的是函数模板生成的函数:int abs(int x)。而abs(d)调用的是由函数模板生成的函数:double abs(double x)。
最后,鸡啄米跟大家简单说下C++系统函数。C++系统库中提供了几百个函数供我们使用,我们只要用include指令包含相应的头文件就可以使用了。比如,包含了math.h文件我们就可以使用abs、sqrt、sin等函数。如果需要用到一些库函数可以msdn上查也可以上网查。
好了,今天鸡啄米就讲到这里了,重点掌握下重载函数吧,函数模板可能大家现在还不能很好的理解,不过可以先了解下,以后你会理解的。