c的编程思想之一被称为泛型编程,主要使用的技术是模板
c包括函数模板和http://www.Sina.com/http://www.Sina.com /
函数模板角色:
创建一个用类模板表示的公共函数,但不具体指定函数的返回类型和参数类型
1.函数模板语法
1 .模板类型名称t
2 .声明或定义函数
虚拟的类型
模板:声明模板的创建
typename :后跟的符号是数据类型,表示可以用class替换
t :通用数据类型。 名称是可替换的,通常是大写
语法:
# includeiostreamusingnamespacestd;//两个整数voidswapint(inta,int b ) { int temp=a; a=b; b=temp;//两个浮点数voidswapdouble (双精度,双精度b ) {双精度时间=a; a=b; b=temp; }void test () { int a=10; int b=20; sapint(a,b ); cout'a='aendl; cout'b='bendl; 双精度c=1.1; 双精度d=2.2; swap双精度(c,d ); cout'c='cendl; cout'd='dendl; }int main () { test ); }但是,有很多数据类型,除了int double等以外,还有用户自己定义的结构类型,所以可以看到有无数种。 为了解决这个问题,用模板解决。
代码如下。
//函数模板templatetypename T//typename是classvoidmyswap(ta,T b ) { T temp=a; a=b; b=temp; }模板解释:
让编译器直接判断数据类型,进行运算
# includeiostreamusingnamespacestd; 模板类型名称t//类型名称为classvoidmyswap(ta,T b ) { T temp=a; a=b; b=temp; }void test () { int a=10; int b=20; myswap(a,b ); cout'a='aendl; cout'b='bendl; 双精度c=1.1; 双精度d=2.2; myswap(c,d ); cout'c='cendl; cout'd='dendl; }int main () { test ); } 示例
编译时直接向编译器传达指定的类型
# includeiostreamusingnamespacestd; 模板类型名称t//类型名称为classvoidmyswap(ta,T b ) { T temp=a; a=b; b=temp; }void test () { int a=10; int b=20; myswapint(a,b ); cout'a='aendl; cout'b='bendl; 双精度c=1.1; 双精度d=2.2; myswap双精度(c,d ); cout'c='cendl; cout'd='dendl; }int main () { test ); } ——33543354————————3——33——3————————3——33333——3333——333333——33333333——3333——33——333——33——333——35433333333————
(1).自动类型推导
注意事项:
)1)自动类型导出必须导出一致的数据类型t才能使用
)2)型
板必须要确定出T的数据类型,才可以使用(1)如:
在前文的test函数中: void test(){ int a=10; char c='c'; myswap(a,c)//错误}
(2)如:
template<class T>void func(){ cout<<"hello"<<endl;}void test(){ func();}int main(){ test();}此程序是无法运行的,因为模板没有确定T的数据类型
如果一定要输出,则一定要在调用模板函数时显示数据类型
代码如下:
———————————————————————————————————————
3.函数模板案例
案例描述:
1.利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
2.排序规则从大到小,排序算法为选择排序
3.分别利用char数组和int数组进行测试
代码如下:
———————————————————————————————————————
4.普通模板和函数模板的区别
普通函数调用时可以发生自动类型转换
函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
如果利用显示指定类型的方式,可以发生隐式类型转换
这里不做说明
———————————————————————————————————————
5.普通函数和模板函数的调用规则
1.如果函数模板和普通模板都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板
1.直接上代码
#include<iostream>using namespace std;void myprint(int a,int b){ cout<<"调用的普通函数"<<endl;}template<class T>void myprint(T a,T b){ cout<<"调用的模板"<<endl;}void test(){ int a=10; int b=20; myprint(a,b);}int main(){ test();}运行结果如下:
上面的例子可以轻松看出一点问题,假如普通函数的语句为myprint(int a,int b);打上分号后 该语句会使得报错,那么这时应该要想到用上函数模板
2.可以通过空模板参数列表 强制调用 函数模板
代码如下:
#include<iostream>using namespace std;void myprint(int a,int b);template<class T>void myprint(T a,T b){ cout<<"调用的模板"<<endl;}void test(){ int a=10; int b=20; //通过空模板参数列表,强制调用函数模板 myprint<>(a,b);}int main(){ test();}运行结果如下:
3.函数模板也可以发生重载,这点不做程序上的说明,注意下重载的时函数名,里面的变量类型不一定会相同,因此函数调用时会调用变量类型和数量相同的模板函数。
那么第4点所说的“如果函数模板可以产生更好的匹配,优先调用函数模板”是什么意思呢?
上代码:
运行结果如下:
那么为什么会有这样的结果呢?
那是因为在调用普通函数时,编译器会自动把char类型转化为int类型再做交换,但是相比之下,模板函数则不需要做此变换,编译器会自动选择更简单的模板函数的方式调用该函数。
——————————————————————————————————————
6.模板的局限性
例如:
template
void f(T a,T b)
{
a=b;
}
在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了
再例如:
template
void f(T a,T b)
{
if(a>b){…}
}
在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板
解决方法:
在程序中利用具体化Person的版本实现代码,具体化优先调用
template<>返回值类型 函数名(Person &a,Person &b)
{//写出执行的方式
}