《面向对象的程序设计c++第六章模板演示文档》由会员分享,可在线阅读,更多相关《面向对象的程序设计c++第六章模板演示文档(72页珍藏版)》请在装配图网上搜索。
面向对象程序设计第六章 模板C++ Templates,杨卫东 左峥嵘
华中科技大学 自动化学院,2017秋,参考资料,C++ primer 第四版
Effective C++ 3rd
C++ Templates(简体中文版).pdf,内容,模板的定义
函数模板
类模板
标准模板库STL,问题提出,实现一个函数,输入2个变量,输出这两个变量中值比较大的元素。
要求:此函数可以接受int, char以及double类型的参数。C语言实现:
//函数1
char MaxOfChar( char cNum1, char cNum2)
{
return(cNum1>cNum2)?cNum1:cNum2;
}
//函数2
int MaxOfInt( int iNum1, int iNum2)
{
return(iNum1>iNum2)?iNum1:iNum2;
}
//函数3
double MaxOfDouble( double dNum1, double dNum2)
{
return(dNum1>dNum2)?dNum1:dNum2;
},C语言,函数重载,c++时代,由于存在重载的概念,所以实现起来应该是这个样子:
//函数1
char Max( char cNum1, char cNum2)
{
return(cNum1>cNum2)?cNum1:cNum2;
}
//函数2
int Max( int iNum1, int iNum2)
{
return(iNum1>iNum2)?iNum1:iNum2;
}
//函数3
double Max( double dNum1, double dNum2)
{
return(dNum1>dNum2)?dNum1:dNum2;
}
#define MAX(x,y) ( (x>y) ? x: y ),函数名字统一
但代码量没有什么变化
能否进一步?,C++,宏定义,宏定义
#define Max( Inputl, Input2)
( ( Inputl>Input2) ? Inputl:Input2 )
宏无类型检查,不建议,,模板(函数模板)
template
T Max( const T
}
可以接受任何类型的参数,包括上边提到的int, char, double,甚至任何自定义类型(只要你实现了它的比较运算符operator > )
具体选用什么样的实际函数是在编译时刻就决定好的,丝毫不会影响运行时的效率,,Input参数中用的是const&的,好处是减少函数调用时候的开销,因为我们不知道T类型到底有多大,模板定义,代码重用是程序设计的重要特性,为实现代码重用,使得代码具有更好的通用性,需要代码不受数据类型的限制,自动适应不同的数据类型,实现参数化程序设计。模板是C++中进行通用程序设计的工具之一
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型
如希望函数或类能够处理多种不同类型数据,可以通过模板为函数或类设计一个通用样板(通用数据类型),当处理实际数据时,根据给定数据的实际类型来确定,模板是c++语言最强大却最少被使用的特征之一,便于重复利用已经开发好的数据结构和算法,可以提高代码的复用性和开发效率,是通用编程实现方法之一。
在c++中,模板让程序员能够定义一种使用不同类型对象的行为。比如用模板类定义一种链表,那么通过不同的模板参数(在调用时提供),可以生成不同类型的链表
有点像宏,但是宏不是类型安全的,而模板是类型安全的
分函数模板和类模板两种,模板的特点,6.1 函数模板
1、数据类型作为参数的背景
例:求绝对值的函数
int abs(int x)
{
return x<0?-x:x;
}
double abs(double x)
{
return x<0?-x:x;
}
特点:算法完全相同,仅仅只是数据类型不同。
(函数重载)
问题:能否以数据类型作为参数,实现通用代码设计。,2、模板
模板是由可以使用任何数据类型的通用代码构成。模板以数据类型作为参数。
模板的定义形式是:
template
函数定义
说明:
template是关键字,表示定义的是模板。
括起来的是模板的参数,可以有一个或多个。如:
template
或者:
template,,3、例子 定义一个求绝对值函数的模板。
#include
template
T abs(T x)
{
return x<0?-x:x;
}
void main()
{
int n=-5;
double d=-5.5;
cout<
, 2 > _TD31;,举例2——矩阵,template
class Matrix
{
public:
// constructors and destructor
Matrix();
Matrix( const Matrix ,Test62_TmatrixsDemo.dsw,模板是C++支持参数化的工具
使用类模板使用户可以为类声明一种模式,使类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能够取任意类型。
类模板的声明形式如下:
template
类声明
模板参数表为:
class 标识符;如:template
模板参数表包含上面多项内容时,各项内容以逗号分隔。
模板类的成员函数必须是函数模板,6.2 类模板,在类模板首部以外的成员函数定义都要以下面的形式开头。
template
与函数模板相同,类模板只有使用的时候才被具体化为某一种类型
用模板类创建对象的一般形式:
模板 对象名1,对象名2,…,对象名n;
模板参数表为用逗号分隔的若干类型标识符或常量表达式构成。,6.2 类模板,#include
#include
// 结构体Student
struct Student
{
int id; //学号
float gpa; //平均分
};
template //类模板:实现对任意类型数据进行存取
class Store
{
private:
T item; // item用于存放任意类型的数据
int haveValue; // haveValue标记item是否已被存入内容
public:
Store(void); // 缺省形式(无形参)的构造函数
T GetElem(void); //提取数据函数
void PutElem(T x); //存入数据函数
};,举例,//以下实现各成员函数。
//注意:模板类的成员函数,若在类外实现,则必须是模板函数
// 缺省形式构造函数的实现
template
Store::Store(void): haveValue(0)
{ }
// 提取数据函数的实现
template
T Store::GetElem(void)
{
// 如果试图提取未初始化的数据,则终止程序
if (haveValue == 0)
{
cout << "No item present!" << endl;
exit(1);
}
return item; // 返回item中存放的数据
},// 存入数据函数的实现
template
void Store::PutElem(T x)
{
haveValue++; // 将haveValue 置为 TRUE,表示item中已存入数值
item = x; // 将x值存入item
}
void main(void)
{
Student g= {1000, 23};
//定义Student类型结构体变量的同时赋以初值
Store S1, S2;
//定义两个Store类对象,其中数据成员item为int类型
Store S3;
//定义Store类对象S3,其中数据成员item为Student类型,Store D;
//定义Store类对象D,其中数据成员item为double类型
S1.PutElem(3); //向对象S1中存入数据(初始化对象S1)
S2.PutElem(-7); //向对象S2中存入数据(初始化对象S2)
cout << S1.GetElem() << " " << S2.GetElem() << endl;
//输出对象S1和S2的数据成员
S3.PutElem(g); //向对象D中存入数据(初始化对象D)
cout << "The student id is " << S3.GetElem().id << endl;
//输出对象S3的数据成员
//D.PutElem(6.5);
cout << "Retrieving object D " ;
cout << D.GetElem() << endl; //输出对象D的数据成员
// 由于D未经初始化,在执行函数D.GetElement()过程中导致程序终止
},运行结果:,,//类模板的实现
#ifndef EXAMPLE9_01B_H
#define EXAMPLE9_01B_H
template
T Max::Max(T the first, T thesecond, T thethird):
item1(thefirst),item2(thesecond),item3(thethird)
{
return;
}
template
void Max::SetItem(T thefirst, T thesecond, T thethird)
{
item1=thefirst;
item2=thesecond;
item3=thethird;
}
template
T Max::GetMaxItem(),(续),{
T maxitem;
maxitem=item1>item2 ? item1: item2;
maxitem=maxitem>item3? maxitem: item3;
return maxitem;
}
#endif
//EXAMPLE9_1.CPP
//主程序
#include
#include ″EXAMPLE901.H″
#include ″EXAMPLE901B.H″
void main()
{
Max nmyMax(1,2,3);
Max dblmyMax(1.2,1.3,-1.4);
cout<ptrNext; //一般情况
return ptrTemp;
}
//链表类构造函数,4个私有指针成员设置为空,链表初始长度设置为0,初始当前结点
//初始位置为-1
template
LinkedList::LinkedList(void):ptrFront(NULL),ptrTail(NULL),
ptrPrev(NULL),ptrCurr(NULL),nListLength(0),nPosition(-1)
{ }
//重载″=″号运算符
template
LinkedList& LinkedList::operator=(const LinkedList& list)
{,if(this!=,if(!ptrFront) //如果当前指针为空,链表为空直接返回
{
return;
}
if(nPos>=nListLength||nPosNextListNode();
ptrPrev=ptrFront;
nStartPos=1;
for(nPosition=nStartPos;nPosition!=nPos;nPosition++)
//寻找该位置并使当前指针指向该位置,{
ptrPrev=ptrCurr;
ptrCurr=ptrCurr->NextListNode();
}
}
}
//当前指针指向当前结点的后续结点
template
void LinkedList::Next()
{
if(ptrCurr)
{
ptrPrev=ptrCurr;
ptrCurr=ptrCurr->NextListNode();
nPosition++;
}
}
//将数据为nItem的结点插入到链表头
template,void LinkedList::InsertFront(const T,newListNode=GetListNode(nItem);
ptrCurr->InsertAfter(newListNode);
}
}
//将数据为nItem的结点插入到链表的当前位置之前
template
void LinkedList::InsertAt(const T
}
else //一般情况
{,newListNode=GetListNode(nItem);
ptrPrev->InsertAfter(newListNode);
}
if(ptrPrev==ptrTail)
{
ptrTail=newListNode;
nPosition=nListLength;
}
ptrCurr=newListNode;
}
//将数据为nItem的结点插入到链表当前结点之后
template
void LinkedList::InsertAfter(const T
if(!ptrCurr) //处理空链表的情况
{,newListNode=GetListNode(nItem);
ptrCurr=newListNode;
ptrFront=ptrCurr;
}
else //一般情况
{
newListNode=GetListNode(nItem);
ptrCurr->InsertAfter(newListNode);
}
if(ptrPrev==ptrTail)
{
ptrTail=newListNode;
nPosition=nListLength;
}
ptrCurr=newListNode;
nListLength++;
}
//删除链表中的当前结点
template
void LinkedList::DeleteCurr(),{
ListNode *ptr;
if(!ptrCurr) //处理空链表的情况
{
cerrNextListNode();
}
else //一般情况
ptr=ptrPrev->DeleteAfter();
if(ptr==ptrTail)
{
ptrTail=ptrPrev;
nPosition--;
}
ptrCurr=ptr->NextListNode();
FreeListNode(ptr);,nListLength--;
}
//删除链表中所有结点并释放资源
template
void LinkedList::DeleteAll()
{
ListNode *ptrCurrPos,
*ptrNextPos;
ptrCurrPos=ptrFront;
while(ptrCurrPos) //循环处理删除链表中的各个结点
{
ptrNextPos=ptrCurrPos->NextListNode();
FreeListNode(ptrCurrPos);
ptrCurrPos=ptrNextPos;
}
ptrFront=NULL;
ptrTail=NULL;
ptrPrev=NULL;
ptrCurr=NULL;,nListLength=0;
nPosition=-1;
}
//删除链表的头结点
template
int LinkedList::DeleteHead()
{
ListNode *ptr=ptrFront;
if(ptrFront)
{
ptrFront=ptrFront->NextListNode();
delete ptr;
nListLength--;
return 1;
}
else //处理链表为空的情况
{
cout<<″The List is empty!″<ShowDate());
ptr=ptr->NextListNode();
}
if(nPosition==-1) //list为空
return;
ptrPrev=NULL;
ptrCurr=ptrFront;
for(int nPos=0;nPos!=list.CurrPosition();nPos++)
//将新链表的各个数据成员设置与原链表相同
{
ptrPrev=ptrCurr;
ptrCurr=ptrCurr->NextListNode();
}
nPosition=nPos;
nListLength=list.ListLength();
},//获得下一个新结点,返回新结点地址
template
ListNode *LinkedList::GetListNode(const T,ptrCurr=ptrCurr->NextListNode();
}
}
//在链表中查找数据
template
int LinkedList::Find(T
}
//删除链表中满足条件的结点
template,void LinkedList::Delete(T key)
{
ptrCurr=ptrFront;
ptrPrev=NULL;
if(!ptrCurr)
return;
while(ptrCurr
}
}
//在排序链表中插入新结点构成新的排序链表,template
void LinkedList::InsertOrder(T nItem)
{
ListNode *newListNode,
*next, //用于遍历链表
*prev; //next指向结点的前一个结点的指针
ptrPrev=NULL;
ptrCurr=ptrFront;
prev=ptrCurr;
next=ptrCurr->NextListNode();
while((prev->ShowDate()==next->ShowDate()) //如果原链表中所有结点均相等,则将结点
//作为原链表的首结点
else if(prev->ShowDate()>next->ShowDate()) //降序排列时
{,while(ptrCurr) //寻找插入位置
{
if(nItem>=ptrCurr->ShowDate()) break;
ptrPrev=ptrCurr;
ptrCurr=ptrCurr->NextListNode();
}
if(!ptrPrev) InsertFront(nItem);
else
{
newListNode=GetListNode(nItem);
ptrPrev->InsertAfter(newListNode);
}
}
else //升序排列时
{
while(ptrCurr) //寻找插入位置
{
if(nItemShowDate()) break;
ptrPrev=ptrCurr;
ptrCurr=ptrCurr->NextListNode();
},(续),if(!ptrPrev) InsertFront(nItem);
else
{
newListNode=GetListNode(nItem);
ptrPrev->InsertAfter(newListNode);
}
}
}
#endif,应用类模板过程中,在类外实现成员函数时要注意不要漏写template 。同时,所有涉及类模板的地方都要用。,谢 谢 !,,
链接地址:https://www.zhuangpeitu.com/p-360177.html