目录
(一)函数模板
一般定义形式
模板函数重载
函数模板参数
带有多类型参数的函数模板
(二)类模板
类模板的使用
int max(int a,int b);
float max(float a,float b);
double max(double a,double b);
如上这三个重载函数,他们的操作相同,都是求两个数中的最大值。为了避免逐个定义重载函数的繁琐编程,由于函数模板使用通用数据类型定义函数,因此使用函数模板完成这项工作更为简洁和方便。
template //template函数模板关键字;T为通用数据类型
返回类型 FunctionName(数据参数表) //FunctionName函数模板名
{
函数模板定义体; //接上,T可为基本数据类型或类类型,需加前缀class和typename
}
例如对之前的三个重载函数进行模板化,为:
template
T max(T a,T b)
{
return a>b?a:b; //T作为返回类型和参数类型
}
函数模板只是函数的描述,表示它每次能单独处理类型形参表中说明的数据类型。它不是一个实实在在的函数,是以具体类型为实参来生成函数体的模板,编译系统不为其产生任何执行代码。使用函数模板可以根据特定的数据类型,产生一个该模板的实例,该函数可以像普通函数一样调用。
#include
using namespace std;
template
T abs(T n)
{
return (n<0)?-n:n;
}
int main()
{
int int1 = 5;
int int2 = -6;
long lon1 = 70000L;
long lon2 = -80000L;
double dub1 = 9.95;
double dub2 = -10.15;
//模板函数的实例化
cout<<"\nabs("<
cout<<"\nabs("<
cout<<"\nabs("<
cout<<"\nabs("<
cout<<"\nabs("<
cout<<"\nabs("<
cout<
在编译程序时,输入参数的类型与重载函数的参数类型隐式转换后一致时,调用重载函数,否则调用模板函数(由于博客和书的结论不太一样,并且不知道该听谁的,于是。。。自己总结了)。
#include
using namespace std;
template
T Max(T a, T b) {
cout << "\nT Max(T a,T b)" << endl;
return a > b ? a : b;
}
int Max(int a, int b) {
cout << "\nint Max(int a,int b)" << endl;
return a > b ? a : b;
}
template
T Max(T a, T b,T c) {
cout << "\nT Max(T a,T b,T c)" << endl;
return Max(Max(a, b), c);
}
int main() {
int a = 1;
int b = 2;
cout << Max(a, b) << endl; //当函数模板和普通函数模板都符合时,优先选择普通函数
cout << Max<>(a, b) << endl; //若显示使用函数模板,则使用<>类型列表
cout << Max(3.0, 4.0) << endl; //如果函数模板可以产生一个更好的匹配,则选择模板
cout << Max(5.0, 6.0, 7.0) << endl; //重载
cout << Max('a', 100) << endl; //调用普通函数可以隐式类型转换
return 0;
}
结果
int Max(int a,int b)
2
T Max(T a,T b)
2
T Max(T a,T b)
4
T Max(T a,T b,T c)
T Max(T a,T b)
T Max(T a,T b)
7
int Max(int a,int b)
100
请按任意键继续. . .
函数模板中的数据形参分为:
(1)引用型参数:可提高参数传递效率。
(2)非引用型参数: template
形式如下:
template
[return-type] function_name(T1 param1,T2 param2...);
//return-type 为返回类型,既可以是一个具体的类型,也可以是 T1、T2中的通用数据类型。
Template
TRetun max(TArg a,TArg b)
{
return a > b ? a : b;
}
#include
using namespace std;
template void display(T1 x,T2 y)
{
cout<
使用模板生成对象时自动创建该模板的一个实例——模板类,也可以显式声明模板类。模板类主要用于容器类,这些类可以包含以特定方式组织起来的给定类型的对象集。例如数组、堆栈、链表,他们所使用的存储方式独立于操作对象的类型。类模板提供的工具,可以定义存储任意类型的对象的容器,模板的参数可用于指定容器存储的对象类型。
类模板定义及实现的一般形式如下:
template<类型形式参数表> class className
{
//类声明体
};
template<类型形式参数表>
返回类型className<类型名表>::MemberFuncName1(形式参数表)
{
//成员函数定义体
}
...
template<类型形式参数表>
返回类型className<类型名表>::MemberFuncNameN(形式参数表)
{
//成员函数定义体
}
定义和实现一个单向链表的模板类:
//list.h
#include
using namespace std;
template class List
{
public:
List();
void Add(T&); //添加结点
void Remove(T&); //删除结点
T* Find(T&); //查找结点
void PrintList(); //打印链表
~List();
protected:
struct Node //结构结点
{
Node* pNext;
T* pT;
};
Node *pFirst; //链首节点指针
};
templateList::List()
{
pFirst = 0;
}
template void List::Add(T& t) //头插法
{
Node* temp = new Node; //从堆空间中申请一个结点
temp->pT = &t; //将T对象挂载在这个节点上
temp->pNext = pFirst; //将该结点指向链首的结点
pFirst = temp; //将该节点成为链首
}
template void List::Remove(T& t)
{
Node* q = 0; //用来点位待删除的结点
if(*(pFirst->pT)==t) //T类中==需有定义
{
q = pFirst;
pFirst = pFirst -> pNext; //带删除结点在链首时的脱链
}
else
{
for(Node* p = pFirst; p -> pNext; p = p -> pNext)
{
if(*(p -> pNext -> pT) == t)
{
q = p -> pNext;
p -> pNext = q -> pNext;
break;
}
}
}
if(q)
{
delete q -> pT; //删除节点上的T类对象
delete q; //删除结点
}
}
template T* List::Find(T& t)
{
for(Node* p = pFirst; p; p = p -> pNext)
if(*(p -> pT) == t)
return p -> pT;
return 0;
}
template void List::PrintList()
{
for(Node* p = pFirst; p; p = p -> pNext)
cout<<*(p -> pT)<<" ";
cout< List::~List()
{
Node *p;
while( p = pFirst )
{
pFirst = pFirst -> pNext;
delete p -> pT;
delete p;
}
pFirst = 0;
}
类模板实例创建方式
className<类型实参表> object;
使用实例
// singleList.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include "list.h"
using namespace std;
int main()
{
//创建模板类List和该对象
List floatList;
//创建和遍历浮点链表
for(int i = 1; i < 7; i ++)
floatList.Add(*new float(i + 0.6));
floatList.PrintList();
//查找并删除结点
float b = 3.6;
float* pa = floatList.Find(b);
if(pa)
floatList.Remove(*pa);
floatList.PrintList();
return 0;
}
结果
6.6 5.6 4.6 3.6 2.6 1.6
6.6 5.6 4.6 2.6 1.6
请按任意键继续. . .