C++语言程序设计(第4版)第九章群体类和群体数据的组织清华大学郑莉C++语言程序设计(第4版),郑莉,清华大学目录9.1函数模板与类模板9.2线性群体9.3群体数据的组织9.4综合实例——对个人银行账户管理程序的改进9.5深度探索9.6小结2C++语言程序设计(第4版),郑莉,清华大学9.1.1函数模板•函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计。•定义方法:template模板参数表函数定义•模板参数表的内容▫类型参数:class(或typename)标识符▫常量参数:类型说明符标识符▫模板参数:template参数表class标识符39.1函数模板与类模板C++语言程序设计(第4版),郑莉,清华大学4例:求绝对值函数的模板#includeiostreamusingnamespacestd;templatetypenameTTabs(Tx){returnx0?-x:x;}intmain(){intn=-5;doubled=-5.5;coutabs(n)endl;coutabs(d)endl;return0;}9.1函数模板与类模板——9.1.1函数模板运行结果:55.5C++语言程序设计(第4版),郑莉,清华大学求绝对值函数的模板分析•编译器从调用abs()时实参的类型,推导出函数模板的类型参数。例如,对于调用表达式abs(n),由于实参n为int型,所以推导出模板中类型参数T为int。•当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数:intabs(intx){returnx0?–x:x;}59.1函数模板与类模板——9.1.1函数模板C++语言程序设计(第4版),郑莉,清华大学例9-1函数模板的示例//9_1.cpp#includeiostreamusingnamespacestd;templateclassT//定义函数模板voidoutputArray(constT*array,intcount){for(inti=0;icount;i++)coutarray[i];coutendl;}69.1函数模板与类模板——9.1.1函数模板C++语言程序设计(第4版),郑莉,清华大学例9-1(续)intmain(){//主函数constintA_COUNT=8,B_COUNT=8,C_COUNT=20;inta[A_COUNT]={1,2,3,4,5,6,7,8};//定义int数组doubleb[B_COUNT]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8};//定义double数组charc[C_COUNT]=Welcometoseeyou!;//定义char数组coutaarraycontains:endl;outputArray(a,A_COUNT);//调用函数模板coutbarraycontains:endl;outputArray(b,B_COUNT);//调用函数模板coutcarraycontains:endl;outputArray(c,C_COUNT);//调用函数模板return0;}79.1函数模板与类模板——9.1.1函数模板C++语言程序设计(第4版),郑莉,清华大学例9-1(续)•运行结果如下:aarraycontains:12345678barraycontains:1.12.23.34.45.56.67.78.8carraycontains:Welcometoseeyou!89.1函数模板与类模板——9.1.1函数模板C++语言程序设计(第4版),郑莉,清华大学9.1.2类模板•类模板的作用使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。99.1函数模板与类模板C++语言程序设计(第4版),郑莉,清华大学类模板的声明•类模板:template模板参数表class类名{类成员声明}•如果需要在类模板以外定义其成员函数,则要采用以下的形式:template模板参数表类型名类名模板参数标识符列表::函数名(参数表)109.1函数模板与类模板——9.1.2类模板C++语言程序设计(第4版),郑莉,清华大学例9-2类模板示例#includeiostream#includecstdlibusingnamespacestd;structStudent{intid;//学号floatgpa;//平均分};templateclassTclassStore{//类模板:实现对任意类型数据进行存取private:Titem;//item用于存放任意类型的数据boolhaveValue;//haveValue标记item是否已被存入内容public:Store();//缺省形式(无形参)的构造函数T&getElem();//提取数据函数voidputElem(constT&x);//存入数据函数};119.1函数模板与类模板——9.1.2类模板C++语言程序设计(第4版),郑莉,清华大学12例9-2(续)templateclassT//默认构造函数的实现StoreT::Store():haveValue(false){}templateclassT//提取数据函数的实现T&StoreT::getElem(){//如试图提取未初始化的数据,则终止程序if(!haveValue){coutNoitempresent!endl;exit(1);//使程序完全退出,返回到操作系统。}returnitem;//返回item中存放的数据}templateclassT//存入数据函数的实现voidStoreT::putElem(constT&x){//将haveValue置为true,表示item中已存入数值haveValue=true;item=x;//将x值存入item}9.1函数模板与类模板——9.1.2类模板C++语言程序设计(第4版),郑莉,清华大学13例9-2(续)intmain(){Storeints1,s2;s1.putElem(3);s2.putElem(-7);couts1.getElem()s2.getElem()endl;Studentg={1000,23};StoreStudents3;s3.putElem(g);coutThestudentidiss3.getElem().idendl;Storedoubled;coutRetrievingobjectD...;coutd.getElem()endl//由于d未经初始化,在执行函数D.getElement()过程中导致程序终止return0;}9.1函数模板与类模板——9.1.2类模板C++语言程序设计(第4版),郑莉,清华大学线性群体•线性群体的概念•直接访问群体--数组类•顺序访问群体--链表类•栈类•队列类149.2线性群体C++语言程序设计(第4版),郑莉,清华大学群体的概念•群体是指由多个数据元素组成的集合体。群体可以分为两个大类:线性群体和非线性群体。•线性群体中的元素按位置排列有序,可以区分为第一个元素、第二个元素等。•非线性群体不用位置顺序来标识元素。159.2线性群体C++语言程序设计(第4版),郑莉,清华大学9.2.1线性群体的概念•线性群体中的元素次序与其位置关系是对应的。在线性群体中,又可按照访问元素的不同方法分为直接访问、顺序访问和索引访问。•在本章我们只介绍直接访问和顺序访问。169.2线性群体…第一个元素第二个元素第三个元素最后一个元素C++语言程序设计(第4版),郑莉,清华大学9.2.2直接访问群体——数组类•静态数组是具有固定元素个数的群体,其中的元素可以通过下标直接访问。▫缺点:大小在编译时就已经确定,在运行时无法修改。•动态数组由一系列位置连续的,任意数量相同类型的元素组成。▫优点:其元素个数可在程序运行时改变。•vector就是用类模板实现的动态数组。•动态数组类模板:例9-3(Array.h)179.2线性群体C++语言程序设计(第4版),郑莉,清华大学18例9-3动态数组类模板程序#ifndefARRAY_H#defineARRAY_H#includecasserttemplateclassT//数组类模板定义classArray{private:T*list;//用于存放动态分配的数组内存首地址intsize;//数组大小(元素个数)public:Array(intsz=50);//构造函数Array(constArrayT&a);//拷贝构造函数~Array();//析构函数ArrayT&operator=(constArrayT&rhs);//重载=“T&operator[](inti);//重载[]”constT&operator[](inti)const;operatorT*();//重载到T*类型的转换operatorconstT*()const;intgetSize()const;//取数组的大小voidresize(intsz);//修改数组的大小};9.2线性群体——9.2.2直接访问群体——数组类C++语言程序设计(第4版),郑莉,清华大学templateclassTArrayT::Array(intsz){//构造函数assert(sz=0);//sz为数组大小(元素个数),应当非负size=sz;//将元素个数赋值给变量sizelist=newT[size];//动态分配size个T类型的元素空间}templateclassTArrayT::~Array(){//析构函数delete[]list;}//拷贝构造函数templateclassTArrayT::Array(constArrayT&a){size=a.size;//从对象x取得数组大小,并赋值给当前对象的成员//为对象申请内存并进行出错检查list=newT[size];//动态分配n个T类型的元素空间for(inti=0;isize;i++)//从对象X复制数组元素到本对象list[i]=a.list[i];}199.2线性群体——9.2.2直接访问群体——数组类例9-3(续)C++语言程序设计(第4版),郑莉,清华大学//重载=运算符,将对象rhs赋值给本对象。实现对象之间的整体赋值templateclassTArrayT&ArrayT::operator=(constArrayT&rhs){if(&rhs!=this){//如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配if(size!=rhs.size){delete[]list;//删除数组原有内存size=rhs.size;//设置本对象的数组大小list=newT[size];//重新分配n个元素的内存}//从对象X复制数组元素到本对象for(inti=0;isize;i++)list[i]=rhs.list[i];}return*this;//返回当前对象的引用}209.2线性群体——9.2.2直接访问群体——数组类例9-3(续)C++语言程序设计(第4版),郑莉,清华大学//重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有越界检查功能templateclassTT&ArrayT::operator[](intn){assert(n=0&&nsize);//检查下标是否越界returnlist[n];//返回下标为n的数组元素}templateclassTconstT&ArrayT::operator[](intn)const{assert(n=