函数模板、类模板

来源:互联网 发布:二维码追溯软件 编辑:程序博客网 时间:2024/04/27 10:57

当我们需要通过函数实现同一类而非同一种功能时,往往会通过一下几种方式来实现,但是他们又或多或少存在着各种各样的缺陷:
1.对函数进行重载,针对每个所需相同行为的不同类型重新实现它。
缺陷:一旦有新类型出现,就要重新添加对应函数。
代码的复用率很低
如果只是返回值类型不同,函数重载无法解决
不易维护
2.将通用的代码放在公共的基础类里面,通过继承来实现
缺陷:无法进行参数检测
代码维护困难
3.宏函数预处理程序
缺陷:宏函数无法进行参数检测
宏所带来的各种隐患易发

由此,我们引入函数模板:
函数模板:代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;template<class T>//这里的class也可替换为typename(尽量使用typename)T Add(T left, T right){     return left + right;}int main(){     cout << Add<int> << endl;     return 0;}

上例是一个实现加法功能的函数模板。

即使我们不给定相应的类型,编译器也会去自动识别它的类型然后调用类型相对应的函数。
在模板定义中,模板参数不能为空
定义模板可以采用template 也可以采用template
但是我们不能用struct来替代typename。
在定义函数时候用T来定义变量a和b 显然a和b的类型也是未知的,我们只有通过实参才能确定模板形参和返回值的类型。

模板函数也可定义为内联函数,不过,inline只能放在模板参数列表之后,返回值之前。

模板形参列表不能为空。

template<class T>//这里的class也可替换为typenameinline T Add(T left, T right){     return left + right;}

模板并不是类或者函数,编译器用模板产生特定类型的类或者函数,成为模板函数实例化。

模板形参只能在模板形参之后到模板声明或定义的末尾之间使用,遵循名字屏蔽规则。

类型参数:参数类型是模糊的需要通过实参对其进行实例化如上例。
非类型参数:参数的类型是确定的
在调用非类型参数的函数时需要采用引用的方式或者显式调用。

模板形参的名字在同一模板形参列表中只能使用一次。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;template<class T>//这里的class也可替换为typenameT Add(T left, T right){     cout<<typeid(left).name()<<endl;     return left + right;}int Add(int left, int right){     return left + right;}int main(){     cout << Add<int>(1, 2) << endl;     cout << Add<>(1.5, 2.5) << endl;     cout << Add(3, 4) << endl;     cout << Add(5, (int)6.1) << endl;//显示类型转换     return 0;}

这里写图片描述

非模板函数可以和一个同名的模板函数同时存在。

如果在调用的时候条件相同,那么会优先调用非模板函数并非编译器生成的函数
如果条件相同要调用模板函数必须显式调用。即Add(a, b);

显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,而且所有的模板参数都应该根据实参演绎出来,即Max<>(a,b),那么它必须去调用模板函数,并且参数类型是由实参推演而来。

模板函数不支持隐式类型转换而普通函数可以

参数推演时,编译器不会进行类型转换,不过,有两种特殊情况:
1.const类型可被非const(引用/指针)调用
2.数组类型/函数——>指针

程序在执行过程中,模板一共被编译了两次:
1.实例化之前,检查模板是否语法错误
2.实例化时,检测模板代码,是否调用有效


函数模板支持重载。

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>using namespace std;template<class T>//这里的class也可替换为typenameT Add(T left, T right){     cout << typeid(left).name() << endl;     return left + right;}template<typename T>T Add(T first, T second, T third){     cout << typeid(left).name() << endl;     return first + second + third;}int main(){     cout << Add<int>(1, 2) << endl;     //cout << Add<>(1.5, 2.5) << endl;     cout << Add<int>(3, 4, 5) << endl;     //cout << Add(5, (int)6.1) << endl;//显示类型转换     return 0;}

这里写图片描述


函数模板的特化

有的时候,通用的模板并不适用于某些类型,这时候就需要对函数模板进行特化。

template<typename T>T Max(T left, T right){     return left > right ? left : right;}int main(){     char* s1 = "dabc";     char* s2 = "adac";     cout << Max(s1, s2) << endl;     return 0;}

这里写图片描述

在上例中,本来的输出结果应该是dabc,但是输出的结果却是adac,这是因为这里比较的并不是两个字符串,而是两个指针的地址大小。

template<typename T>int Max(const T left, const T right){    return left > right ? left : right;}template<>int Max<char*>(char *const left, char *const right){    return strcmp(left, right);}
 1.模板函数必须已经存在 2.和已存在的模板函数的类型必须保持一致

类模板

template<typename T>class List{public:     List()     {          cout << "template" << endl;     }};int main(){     List<int> l;     return 0;}

1、模板函数不允许有缺省参数而类模板确是支持的
2、用类模板定义对象的时候必须在类模板名之后在尖括号内指定实际的类型名

全特化
偏特化

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子学习脑子笨怎么办 四年级孩子数学差怎么办 中考考不好了怎么办 初中没学高中怎么办 数学基础差该怎么办 三年级数学成绩差怎么办 夫妻差6岁怎么办 初一数学很差劲怎么办 三年级孩子成绩差怎么办 初中数学成绩不好怎么办 大人不会算数学怎么办 小学初数学不好怎么办 初中生数学计算能力差怎么办 初中生数学计算差怎么办 初一数学没救了怎么办 五年级英语不好怎么办 三年级孩子学习差怎么办 孩子三年级学习成绩差怎么办 三年级字写不好怎么办 7小孩表达能力差怎么办 孩子考了低分怎么办 初一考300分怎么办 小学三年级成绩不好怎么办 五年级考几分怎么办 思想晚熟的人怎么办 孩子学不好数学怎么办 做作业速度慢怎么办 孩子碎头发太多怎么办 孩子碎发太多怎么办 孩子的作业太多怎么办 爸爸是乙肝孩子怎么办 孩子出生没有奶怎么办 顺产后没有奶水怎么办 还在经常逃课怎么办 老板不重视自己怎么办 孩子不听话爱撒谎怎么办 老师针对我孩子怎么办 小孩动不动就哭怎么办 孩子太拧应该怎么办 孩子贪玩不爱学习怎么办 高二了还不学怎么办