1. 函数模板的调用:
第一种: 函数名 <实际类型1,实际类型2>(参数列表);
显式类型推导 fun<int>(1,2);
第二种: 函数名(参数);
隐形类型推导
2.注意:显示类型推导 参数和推导的类型必须一致。
如果有普通函数和模板函数,在调用时可以用显示调用,省略类型的方式 swap<>(1,2)
3.普通函数和函数模板的区别:
函数只可以有一种数据类型相匹配。模板有多种类型
隐式推导优先使用普通函数,只有普通函数不匹配才使用函数模板
函数模板只有在调用时,才会构建函数,而普通函数是在编译时。
普通函数调用时候可以发生自动类型转换,而函数模板不行。
4.函数模板重载
和普通函数的重载相似。也是同一个作用域类函数名相同参数列表不同。
以下是参数顺序不同的重载
template <class T1,class T2>void swap1(T2 a,T1 b)
template <class T1,class T2>void swap1(T1 a,T2 b)
注意,在函数参数顺序不同的重载中,实例化的时候不可以是相同类型
例如 swap1<int ,int >(1,2)则没法匹配哪个函数。
以下是参数个数不同的重载
template <class T1,class T2> void swap1(T1 a,T2 b)
template <typename T2> void swap1(T2 t)
传入不同的参数,调用不同的版本
练习:写比较 大小函数模板,传入2 3 4数值都可以比较都可以返回最大值
5.函数模板特化
定义:为了解决函数模板的局限性,在定义函数模板时候,直接确定好T的类型。也就是特定的类型模板。
格式: template<class T> 返回值 函数名(类名& 对象){ }
匹配:如果传入的是自定义类型,并且和特化版本匹配,会优先使用特化版本
注意:如果特化后,类型确定才可以使用自定义类型中的成员变量和方法。
9.多文件实现函数模板
在定义函数或者类的时候,会.h和cpp文件,定义和申明分开。
出现连接错误的原因:函数模板是在调用时确定的版本,而调用时.h中没有函数实现,出现连接错误,找不到函数体。
如果分开后,编译会出现连接错误。
第一种办法:在main中#include <xxx.h> 和 #include <xx.cpp>
第二种办法:模板的定义和申明都放在.h头文件中。
10. 函数模板的嵌套
定义:在函数模板中调用另外一个函数模板
练习:写两个Mymax函数模板重载,三个参数中调用两个参数的版本比较
11.函数模板的非类型参数
希望传入函数一个特定的确定参数,但不希望放在小括号中。
可以通过非类型参数实现。在模板<>中加了一个参数,但这个参数不是类型参数,是具体的某一个值。
格式:template<class T,基本数据类型 变量名>
返回值 函数名(T& 变量)
例如:template <class T,int size>
void showArr(T* arr);
注意:在上例子中,size是通过模板传入到函数中,可以当做普通变量使用
非类型参数都是常量,在函数中不允许修改,只可以使用,定义非类型参数变量时候,需要加const。
例子: 写一个函数模板,打印数组的所有内容。(但不可以在参数中加入数组大小)。
二、类模板
类模板和函数模板都是以 template 开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如:
在类 A 中声明了两个类型为T的成员变量 a 和 b,还声明了一个返回类型为 T 带两个参数类型为 T 的函数 hy。
类模板对象的创建:比如一个模板类 A,则使用类模板创建对象的方法为 A m ;在类 A 后面跟上一个 <> 尖括号并在里面填上相应的类型,这样的话类 A 中凡是用到模板形参的地方都会被 int 所代替。当类模板有两个模板形参时创建对象的方法为 A<int, double> m; 类型之间用逗号隔开。
对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如 A<2> m;用这种方法把模板形参设置为 int 是错误的(编译错误:error C2079: ‘a’ uses undefined class ‘A’),类模板形参不存在实参推演的问题。也就是说不能把整型值 2 推演为 int 型传递给模板形参。要把类模板形参调置为 int 型必须这样指定 A m。
在类模板外部定义成员函数的方法为:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}
比如有两个模板形参 T1,T2 的类 A 中含有一个 void h() 函数,则定义该函数的语法为:
template<class T1,class T2> void A<T1,T2>::h(){}。
注意:当在类外面定义类的成员时 template 后面的模板形参应与要定义的类的模板形参一致。模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在 main 函数中声明或定义一个模板。
一、 类模板对象当做函数的参数
//第一种方式,直接传入模板对象
void fun(person<string, int>& per)
//类模板传入方式
template <class T1,class T2>
void fun3(person<T1,T2>& per)
//整个类模板化
template <class T>
void fun4(T& per)
二、类模板继承
普通类继承:class son:public father{}
模板类继承:普通子类继承模板类;
格式:class 子类:public 父类<指定类型>
构建对象:和普通对象的构建一样 类名 对象(参数列表);
类模板继承类模板
格式: template<class T1,class T2>
class son: public person<T1,T2> {}
三、类模板成员函数类外实现
在类模板中,函数的声明和定义都应该在h文件或者在mian的cpp中,在类中声明,在类外定义需要加上模板的类限定符
案例:template <class T1,class T2>
class myson :public person<T1, T2>
{public:int display(T1 x);};
//;类内声明 类外实现(模板类成员函数)
template <class T1,class T2>
int myson<T1, T2>::display(T1 x){}
}