模板概念:模板是建立通用模具,大大提高复用性,将类型参数化。
C++泛式编程思想,主要利用的技术就是模板
C++提供模板机制:函数模板和类模板
函数模板和类模板区别:
① 类模板没有自动类型推导使用方式
② 类模板在模板参数列表中可以有默认参数
一、函数模板
作用:建立通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型代表。
语法:template<typename T>
[template ——声明创建模板]
[typename ——表面其后面的符号是一种数据类型,可以用class替代]
[T ——通用的数据类型,名称可以替换,通常用大写字母]
使用方式:自动类型推导,显示指定类型
注:① 自动类型推导,必须推导出一致的类型类型T,才能使用
② 模板必须要确定出T的数据类型,才可以使用
//函数模板
template<typename T> //声明模板,T是一个通用数据类型
void swapTest(T& a, T &b)
{
T temp = a;
a = b;
b = temp;
}
//排序模板 (从小到大)
template<typename T>
void sortTest(T arr[],int len)
{
for(int i=0;i<len;i++)
{
int min = i; //最小值下标
for(int j=i+1;j<len;j++)
{
//认定最小值 比 遍历的数值小
if(arr[min] > arrp[j])
min = j;
}
//交换min 和 i元素
if(min != i)
swapTest<T>(arr[min],arr[i]);
}
}
int main()
{
int nA = 10; int nB = 20;
float fA = 10.0; float fB = 20.0;
//模板使用方式
swapTest(nA ,nB); //1.自动类型推导
swapTest<float>(fA ,fB); //2.显示指定类型
//排序案例:
char charArr[] = "bacfed";
sortTest<char>(charArr,sizeof(charArr)/sizeof(char));
int intArr[] = {3,4,2,6,1,,7,5,9,8};
sortTest<int>(intArr,sizeof(intArr)/sizeof(int));
system("pause");
return 0;
}
普通函数与函数模板区别:
① 普通函数调用可以发生隐式类型转换
② 函数模板 用自动类型推导,不可发生隐式类型转换
③ 函数模板 用显示指定类型,可以发生隐式类型转换
调用规则:
① 如果函数模板和普通模板都可以调用,优先普通函数
② 可以同空模板参数列表,强制调用函数模板
③ 函数模板可以发生函数重载
④ 如果函数模板可以产生更好匹配,优先函数模板
二、类模板
作用:建立通用类,类中成员 数据类型可以不具体制定,用虚拟的类型代表。
语法:template<class T>
[template ——声明创建模板]
[class ——表面其后面的符号是一种数据类型,可以用typename替代]
[T ——通用的数据类型,名称可以替换,通常用大写字母]
使用方式:自动类型推导,显示指定类型
创建时机:类模板中成员函数在调用时创建。
类模板对象做函数参数:① 指定传入类型 ② 参数模板化 ③ 整个类模板化
//类模板
template<class T1,class T2= int> //默认参数类型
class Person
{
public:
Person(T1 name,T2 age):m_name(name),m_age(age){}
NameType m_name;
AgeType m_age;
}
//1.指定传入类型
void print1(const Person<string,int> &p){}
//2.参数模板化
template<typename T1,typename T2>
void print2(const Person<T1,T2> &p){};
//3.整个类模板化
template<typename T>
void print3(const T &p){};
int main()
{
//使用方法
Person<string,int> p1("Test",18); //指定类型
Person<string> p2("Test2",18); //默认参数类型
//指定传入类型 (print1())
print1(Person<string,int>("TEST",18));
//参数模板化 (print2<string,int>())
print2(Person<string,int>("TEST",18));
//整个类模板化 (print3<Person<string,int>>())
print3(Person<string,int>("TEST",18));
system("pause");
return 0;
}
类模板继承
注意事项:
当子类继承的父类时一个模板时,子类在声明时,要指出父类中T的类型
如果不指定,编译器无法给予子类分配内存
如果要灵活指定父类中T的类型,子类也需要变为模板
template<class T>
class Base
{
T m;
}
//class Son : public Base<int> //必须指定一个类型
//灵活指定父类中T类型,子类也需要是模板
template<class T1,class T2> //T1:父类T类型 ,T2:子类T2类型
class Son : public Base<T1>
{
T2 obj;
}
int main()
{
Son<int,char> s1; //int--父T,char--子T2
system("pause");
return 0;
}