模板
1 定义:
模板把函数或类要处理的数据类型参数化,表现为参数的多态性。 在面向对象技术中,这种机制称为类属。
模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。
模板说明:
模板说明的作用是声明模板中使用的类属参数。
模板说明的形式为: template<class T1,class T2,…,class Tn>
采用关键字template开始,之后是采用“<>”相括的形式类型参数(类属参数)表,每一个参数前都加有关键字class,Ti是用户定义的标识符,前缀class指定它们为类属参数,即可以实例化为任何内部类型或用户自定义类型。
2 函数模板
2.1 函数模板与模板函数
一般函数是对相同类型数据对象操作的抽象。函数模板是对相同逻辑结构(不同数据类型)数据对象操作的抽象,是生成不同类型参数重载函数的模板。
函数模板=模板说明+函数定义
例:求两个数中的最大值
//定义函数模板,先说明模板的类属参数T,然后是函数的实现定义
template<typename T>
T Max<const T a,const T b>
{return a>b?a:b;}
//函数
#include"Max.h"
#include<ioistream.h>
void main(){
int j,k;
cin>>j>>k;
cout<<Max(j,k)<<endl;
doubel x,y;
cin>>x>>y;
cout<<Max(x,y)<<endl;
}
分析:函数模板Max不是真正的函数,仅仅是一个提供生成不同类型参数重载函数版本的“模板”而已。
第一步:编译阶段,编译器根据调用语句中实际参数的类型对函数模板实例化,生成可运行的函数即:
T Max<const T a,const T b>
{return a>b?a:b;}
将T替换为int,double
int Max<const int a,const int b>
{return a>b?a:b;}
double Max<const double a,const double b>
{return a>b?a:b;}
函数模板与模板函数关系:这些重载函数,通过函数模板按照实际类型生成,成为模板函数,这个过程成为实例化,即:函数模板实例化后成为了模板函数。
第二步:运行阶段,实参与形参进行结合,之心对应的模板函数。
定义冒泡排序的函数模板
template<typename T>
void SortBubble(T *a,int size)
{
int i,work;
T temp;
for(int i=0;i<size;i++){
work=1;
for(int j=i+1;j<size;j++){
if(a[i]->data>a[j]->data){
temp=a[i]->data;
a[i]->data=a[j]->data;
a[j]->data=temp;
work=0;
}
if(work) break;
}
}
}
2.2 重载函数模板
2.2.1 函数模板的重载
重载函数模板便于定义类属参数,或者函数参数的类型、个数不相同所进行的类似操作。
Max函数模板可以重载为求数组最大元素的函数模板。
T Max(const T *a,int n)
{
T temp;
int i=0;
temp=a[0];
for(i;i<n;i++){
if(a[i]>a[i+1])
{
temp=a[i];
}
}
return temp;
}
与Max同名,是重载的函数模板。
2.2.2 用普通函数重载模板
前言: 函数模板实例化时,实际参数类型替换类属参数,虽然这种参数具有类型检查的功能,却没有普通传值参数的类型转换机制。
对于函数模板
T Max<const T a,const T b>
{return a>b?a:b;}
进行调用时,对应的两个实际参数必须类型相同,否则将出现语法错误。
int k,char c;//与Max(int ,char)无法匹配
问题:typename不知道二者之间可以进行隐式类型转换
解决:使用非模板函数进行重载
int Max(const int k,const char c)
//可以**隐式的进行类型转换**
{return k>c? a:b;}
存在隐患:重载函数会导致函数调用的二义性
如果重载函数为**int Max(int,int)则会与T Max(T,T)产生歧义
编译器调用函数的匹配过程如下:
-
寻找和使用最符合函数名和参数类型的模板函数,找到则调用;
-
否则,寻找一个函数模板,将其实例化产生一个可以匹配的模板函数,找到则调用;
-
否则,寻找可以通过类型转换进行参数匹配的重载函数,找到则调用。
-
否则调用错误。
如果调用有多于一个的匹配选择,则调用匹配出现二义性,也是错误的。
3 类模板
3.1 类模板与模板类
一个类模板是类定义的一种模式,用于实现数据类型参数化的类。
类模板=模板说明+类说明
template <typename Type>//模板说明
class TClass //类说明
{
//TClass 的成员函数
private DateMember;
}
类属参数必须至少在类说明中出现一次
类模板的成员函数都是函数模板,实现语法和函数模板类似,如果在类中定义成员函数(inline),不需要特别说明,如果在类外定义,则每个成员函数定义都要冠以模板参数说明,并且指定类名时,后要跟类属参数。
例如:**template开头,用Array:😗*表示类模板的成员函数.
template<typename T> Array<T>::Array(int s){ }
- 当类模板实例化时,成员函数同时实例化为模板函数。
- 声明一个对象的时候,必须用实际类型参数替换类属参数,将类模板实例化为模板类,类型参数用尖括号表示。
- 创建对象:ArrayIntry(6);//用int 实例化,建立模板类对象。
3.2 类模板作为函数参数
函数的形式参数类型可以是类模板或类模板的引用。调用时对应的实际参数是该类模板实例化的模板类对象。
当一个函数拥有类模板参数时,这个函数必定是函数模板。
3.3 在类层次中的类模板
4 标准模板
**前言:**C++包含一个有许多组件的标准库。标准模板库(STL)中有三个组件:容器(container)、迭代器(iterator)和算法(algorithm)。利用标准模板库进行编程,可以节省大量的时间和精力。
4.1 容器
“容器”是数据结构,是包含对象的对象。STL库提供的容器是常用数据结构的类模板(抽象了数据元素的具体类型,只关心结构的组织和算法,就是类模板)
1 容器分类
(1)顺序容器—提供顺序表的表示和操作
vector(向量):随机访问序列中的单个元素,在序列尾快速的插入和删除元素。如果在序列中插入和删除元素,时间和序列长度成正比。
deque(双向队列):随机访问序列中的单个元素,可以在序列的头或尾快速插入和删除元素。如果在序列中插入和删除元素,时间和序列长度成正比。
list(双向链表):用动态链式存放数据,可以从任何位置快速插入和删除元素。
C语言中的数组和string也是一种容器,称为近容器。
(2)关联容器—提供集合和映像的表示和操作
set(集合):不允许重复值,快速查找。
multiset(集合):允许重复值,快速查找。
map(映像):一对一映射,不允许重复值;基于关键字的快速查找。
multimap(映像):一对多映射,允许重复值;基于关键字的快速查找。
(3)容器适配器----特殊顺序表
stack(堆栈):后进先出(LIFO)表,只能在表头插入和删除元素。
queue(队列):先进先出(FIFO)表,只能在表头删除元素,在表尾插入元素。
priority_queue(优先队列):优先级最高的元素总是第一个出列。