模板
1. 模板:通用的模具
- 特点:
- 不可直接使用,只是一个框架
- 模板的通用不是万能的
- 作用:
- 提高复用性
- 将类型参数化
2 函数模板
-
泛型编程主要利用的是模板
-
两种模板机制:函数模板和类模板
2.1 函数模板
-
作用:建立一个通用函数,其函数返回值类型和形参类型可不具体定制,用一个虚拟类型来代表
-
格式:
template <typename T> //template 声明创建模板 //typename 表示其后面的符号一种数据类型,可用class代替 //typename 函数模板 class 类模板 //T 通用的数据类型,名称可代替,通常为大写字母 函数声明或定义
-
使用方法
- 自动类型推导(可根据变量类型自动推导)
- 显示指定类型
函数名<typename>();
-
注意:
- 自动类型推导,必推导出一致的数据类型T,才可使用
- 模板必须要确定出T的数据类型才可使用
-
与普通函数的区别
- 普通函数调用时可发生自动类型转换(意识类型转换)
- 函数模板调用时,若利用自动类型推导,则不会发生饮食类型转换,若利用显示指定类型的方式,则可发生隐式类型转换
-
调用规则
- 若函数模板和普通函数均可实现,则优先调用普通函数
- 可通过空模板参数列表来强制调用函数模板,即
函数名<>(参数);
- 函数模板也可发生重载
- 若函数模板可更好地匹配优先调用函数模板(例普通函数需进行隐式类型转换,而模板可直接调用的话)
-
局限性
- 例1:赋值时,数组无法直接给数组赋值
- 例2:自定义数据类型无法直接进行大小比较
-
解决
-
运算符重载
-
利用具体化的模板
//例 template<> ReturnType 函数名(类型名 &t1,类型名 &t2){}
-
2. 类模板
2.1 类模板
-
作用:建立一个通用类,类中成员数据类型可不具体制定,用一个虚拟类型来代表。
-
格式
template <typename T> //template 声明创建模板 //typename 表示其后面的符号一种数据类型,可用class代替 //typename 函数模板 class 类模板 //T 通用的数据类型,名称可代替,通常为大写字母 类
-
与函数模板的区别
-
类模板无自动类型推导
-
在模板参数列表中可有默认参数
ClassName<参数类型1,参数类型2,...>t(参数1,参数2); //无论是参数类型还是参数均不可省略
-
-
创建时机
- 普通类的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才可创建
2.2 类模板对象做函数参数
-
传入方式
-
指定传入类型 直接显示对象的数据类型
ClassName<参数类型1,参数类型2,...>t(参数1,参数2,...); ReturnType 函数名(ClassName<参数类型1,参数类型2,...>&t){}
-
参数模板化 将对象中的参数变为模板进行传递
template<class T1,class T2> ClassName<参数类型1,参数类型2,...>t(参数1,参数2,...); ReturnType 函数名(ClassName<T1,T2,...>&t){}
-
整个类模板化 将这个对象类型模板化进行传递
template<class T> ClassName<参数类型1,参数类型2,...>t(参数1,参数2,...); ReturnType 函数名(T &t){}
-
2.3 类模板与继承
- 注意:
- 若子类继承的父类是一个类模板时,子类在声明时,要指出父类T的类型。若不指定,编译器无法给子类分配内存,若想灵活指定T的类型,子类也需变为类模板。
2.4 类模板成员函数类外实现
-
构造函数的实现
template<class T1,class T2> class ClassName{ ClassName(T1 t1,T2 t2); ReturnType 函数名(参数); }
-
普通成员函数的实现
template<class T1,class T2> ClassName<T1,T2>::ClassName(T1 t1,T2 t2){} ReturnType ClassName<T1,T2>::函数名(参数){}
2.5 类模板分文件编写
-
问题:类模板中的成员函数创建时机是在调用阶段,导致分文件编写时链接不到
-
解决:
- 解法1:直接包含.cpp源文件
- 解法2:将声明和实现写在同一文件里,并更改后缀名为.hpp(并非强制)
2.6 类模板和友元
-
全局函数类内实现——直接在类内声明友元
friend ReturnType 函数名(ClassName<T1,T2> t){}
-
全局函数类外实现——直需要提前让编译器知道全局函数的存在
//首先得声名类 template<class T1,class T2> class ClassName; //类外实现 template<class T1,class T2> ReturnType 函数名(ClassName<T1,T2> t){} class ClassName{ friend ReturnType 函数名(ClassName<T1,T2> t); }