C++语言程序设计进阶 (5).pdf
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《C++语言程序设计进阶 (5).pdf》由会员分享,可在线阅读,更多相关《C++语言程序设计进阶 (5).pdf(42页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 第九章 模板与群体数据 本章主要内容 函数模板与类模板 线性群体 群体数据的组织 函数模板 思考:如果重载的函数,其解决问题的逻辑是一致的、函数体语句相同,只是处理的数据类型不同,那么写多个相同的函数体,是重复劳动,而且还可能因为代码的冗余造成不一致性。解决:使用模板 例:求绝对值函数的模板 函数模板定义语法 语法形式:template 函数定义 模板参数表的内容 类型参数:class(或typename)标识符 常量参数:类型说明符 标识符 模板参数:template class 标识符 例 9-1 函数模板的示例/9_1.cpp#include using namespace std;t
2、emplate /定义函数模板 void outputArray(const T*array,int count)for(int i=0;i count;i+)cout arrayi ;cout endl;int main()const int A_COUNT=8,B_COUNT=8,C_COUNT=20;int a A_COUNT=1,2,3,4,5,6,7,8;double bB_COUNT=1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8;char cC_COUNT=Welcome!;cout a array contains:endl;outputArray(a,A_CO
3、UNT);cout b array contains:endl;outputArray(b,B_COUNT);cout c array contains:endl;outputArray(c,C_COUNT);return 0;运行结果如下:a array contains:1 2 3 4 5 6 7 8 如果数组元素是类的对象,需要该对象所属类重载了流插入运算符“”b array contains:1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 c array contains:W e l c o m e!注意 一个函数模板并非自动可以处理所有类型的数据 只有能够进行函数模板
4、中运算的类型,可以作为类型实参 自定义的类,需要重载模板中的运算符,才能作为类型实参 类模板 类模板的作用 使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。类模板的声明 类模板:template class 类名 类成员声明;如果需要在类模板以外定义其成员函数,则要采用以下的形式:template 类型名 类名:函数名(参数表)例 9-2 类模板示例#include#include using namespace std;struct Student int id;/学号 float gpa
5、;/平均分;template class Store/类模板:实现对任意类型数据进行存取 private:T item;/item用于存放任意类型的数据 bool haveValue;/haveValue标记item是否已被存入内容 public:Store();T&getElem();/提取数据函数 void putElem(const T&x);/存入数据函数;template Store:Store():haveValue(false)template T&Store:getElem()/如试图提取未初始化的数据,则终止程序 if(!haveValue)cout No item pres
6、ent!endl;exit(1);/使程序完全退出,返回到操作系统。return item;/返回item中存放的数据 template void Store:putElem(const T&x)/将haveValue 置为true,表示item中已存入数值 haveValue=true;item=x;/将x值存入item int main()Store s1,s2;s1.putElem(3);s2.putElem(-7);cout s1.getElem()s2.getElem()endl;class Store private:int item;bool haveValue;public:S
7、tore();int&getElem();void putElem(const int&x);Student g=1000,23;Store s3;s3.putElem(g);cout The student id is s3.getElem().id endl;Store d;cout Retrieving object D.;cout d.getElem()endl /d未初始化,执行函数D.getElement()时导致程序终止 return 0;线性群体的概念 群体是指由多个数据元素组成的集合体。群体可以分为两个大类:线性群体和非线性群体。线性群体中的元素按位置排列有序,可以区分为第一
8、个元素、第二个元素等。非线性群体不用位置顺序来标识元素。线性群体中的元素次序与其逻辑位置关系是对应的。在线性群体中,又可按照访问元素的不同方法分为直接访问、顺序访问和索引访问。在本章我们只介绍直接访问和顺序访问。数组类模板 静态数组是具有固定元素个数的群体,其中的元素可以通过下标直接访问。缺点:大小在编译时就已经确定,在运行时无法修改。动态数组由一系列位置连续的,任意数量相同类型的元素组成。优点:其元素个数可在程序运行时改变。vector就是用类模板实现的动态数组。例 9-3 动态数组类模板程序#ifndef ARRAY_H#define ARRAY_H 第一个元素 第二个元素 第三个元素最后
9、一个元素class Store private:Student item;bool haveValue;public:Store();Student&getElem();void putElem(const Student&x);#include template /数组类模板定义 class Array private:T*list;/用于存放动态分配的数组内存首地址 int size;/数组大小(元素个数)public:Array(int sz=50);/构造函数 Array(const Array&a);/复制构造函数 Array();/析构函数 Array&operator=(cons
10、t Array&rhs);/重载=“T&operator (int i);/重载”const T&operator (int i)const;/重载”常函数 operator T*();/重载到T*类型的转换 operator const T*()const;int getSize()const;/取数组的大小 void resize(int sz);/修改数组的大小;为什么有的函数返回引用 如果一个函数的返回值是一个对象的值,就是右值,不能成为左值。如果返回值为引用。由于引用是对象的别名,通过引用可以改变对象的值,因此是左值。template Array:Array(int sz)/构造函数
11、 assert(sz=0);/sz为数组大小(元素个数),应当非负 size=sz;/将元素个数赋值给变量size list=new T size;/动态分配size个T类型的元素空间 template Array:Array()/析构函数 delete list;template Array:Array(const Array&a)/复制构造函数 size=a.size;/从对象x取得数组大小,并赋值给当前对象的成员 list=new Tsize;/动态分配n个T类型的元素空间 for(int i=0;i size;i+)/从对象X复制数组元素到本对象 listi=a.listi;/重载=运
12、算符,将对象rhs赋值给本对象。实现对象之间的整体赋值 template Array&Array:operator=(const Array&rhs)if(&rhs!=this)/如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配 if(size!=rhs.size)delete list;/删除数组原有内存 size=rhs.size;/设置本对象的数组大小 list=new Tsize;/重新分配size个元素的内存 /从对象X复制数组元素到本对象 for(int i=0;i size;i+)listi=rhs.listi;return*this;/返回当前对象的引用 /重
13、载下标运算符,实现与普通数组一样通过下标访问元素,具有越界检查功能 template T&Array:operator(int n)assert(n=0&n size);/检查下标是否越界 return listn;/返回下标为n的数组元素 template const T&Array:operator(int n)const assert(n=0&n size);/检查下标是否越界 return listn;/返回下标为n的数组元素/重载指针转换运算符,将Array类的对象名转换为T类型的指针 template Array:operator T*()return list;/返回当前对象中私
14、有数组的首地址 指针转换运算符的作用#include using namespace std;void read(int*p,int n)for(int i=0;i pi;int main()int a10;read(a,10);return 0;#include Array.h#include using namespace std;void read(int*p,int n)for(int i=0;i pi;int main()Array a(10);read(a,10);return 0;/取当前数组的大小 template int Array:getSize()const return
15、 size;/将数组大小修改为sz template void Array:resize(int sz)assert(sz=0);/检查sz是否非负 if(sz=size)/如果指定的大小与原有大小一样,什么也不做 return;T*newList=new T sz;/申请新的数组内存 int n=(sz size)?sz:size;/将sz与size中较小的一个赋值给n /将原有数组中前n个元素复制到新数组中 for(int i=0;i n;i+)newListi=listi;delete list;/删除原数组 list=newList;/使list指向新数组 size=sz;/更新siz
16、e#endif /ARRAY_H 例 9-4 数组类应用举例 例 9-4 Array 类的应用 求范围2N中的质数,N在程序运行时由键盘输入。#include#include#include Array.h using namespace std;int main()/用来存放质数的数组,初始状态有10个元素 Array a(10);int n,count=0;cout=2 as upper limit for prime numbers:;cin n;for(int i=2;i=n;i+)/检查i是否能被比它小的质数整除 bool isPrime=true;for(int j=0;j cou
17、nt;j+)/若i被aj整除,说明i不是质数 if(i%aj=0)isPrime=false;break;if(isPrime)if(count=a.getSize()a.resize(count*2);acount+=i;for(int i=0;i count;i+)cout setw(8)ai;cout endl;return 0;链表的概念与结点类模板 顺序访问的线性群体链表类 链表是一种动态数据结构,可以用来表示顺序访问的线性群体。链表是由系列结点组成的,结点可以在运行时动态生成。每一个结点包括数据域和指向链表中下一个结点的指针(即下一个结点的地址)。如果链表每个结点中只有一个指向后继
18、结点的指针,则该链表称为单链表。单链表 单链表的结点类模板 template class Node private:Node*next;public:T data;Node(const T&item,Node*next=0);void insertAfter(Node*p);Node*deleteAfter();Node*nextNode()const;在结点之后插入一个结点 template void Node:insertAfter(Node*p)/p 节点指针域指向当前节点的后继节点 p-next=next;next=p;/当前节点的指针域指向 p 删除结点之后的结点 Node*Node
19、:deleteAfter(void)Node*tempPtr=next;if(next=0)return 0;next=tempPtr-next;return tempPtr;例 9-5 结点类模扳/Node.h#ifndef NODE_H#define NODE_H/类模板的定义 template class Node private:Node*next;/指向后继结点的指针 public:T data;/数据域 Node(const T&data,Node*next=0);/构造函数 void insertAfter(Node*p);/在本结点之后插入一个同类结点p Node*delete
20、After();/删除本结点的后继结点,并返回其地址 Node*nextNode();/获取后继结点的地址 const Node*nextNode()const;/获取后继结点的地址;/类的实现部分 /构造函数,初始化数据和指针成员 template Node:Node(const T&data,Node*next=0):data(data),next(next)/返回后继结点的指针 template Node*Node:nextNode()return next;/返回后继结点的指针 template const Node*Node:nextNode()const return next;/
21、在当前结点之后插入一个结点p template void Node:insertAfter(Node*p)p-next=next;/p结点指针域指向当前结点的后继结点 next=p;/当前结点的指针域指向p /删除当前结点的后继结点,并返回其地址 template Node*Node:deleteAfter()Node*tempPtr=next;/将欲删除的结点地址存储到tempPtr中 if(next=0)/如果当前结点没有后继结点,则返回空指针 return 0;next=tempPtr-next;/使当前结点的指针域指向tempPtr的后继结点 return tempPtr;/返回被删除
22、的结点的地址#endif/NODE_H 链表的基本操作 生成链表 插入结点 查找结点 删除结点 遍历链表 清空链表 例 9-6 链表类模板/LinkedList.h#ifndef LINKEDLIST_H#define LINKEDLIST_H#include Node.h template class LinkedList private:/数据成员:Node*front,*rear;/表头和表尾指针 Node*prevPtr,*currPtr;/记录表当前遍历位置的指针,由插入和删除操作更新 int size;/表中的元素个数 int position;/当前元素在表中的位置序号。由函数r
23、eset使用 /函数成员:/生成新结点,数据域为item,指针域为ptrNext Node*newNode(const T&item,Node*ptrNext=NULL);/释放结点 void freeNode(Node*p);/将链表L 拷贝到当前表(假设当前表为空)。/被拷贝构造函数、operator=调用 void copy(const LinkedList&L);public:LinkedList();/构造函数 LinkedList(const LinkedList&L);/拷贝构造函数 LinkedList();/析构函数 LinkedList&operator=(const Li
24、nkedList&L);/重载赋值运算符 int getSize()const;/返回链表中元素个数 bool isEmpty()const;/链表是否为空 void reset(int pos=0);/初始化游标的位置 void next();/使游标移动到下一个结点 bool endOfList()const;/游标是否到了链尾 int currentPosition()const;/返回游标当前的位置 void insertFront(const T&item);/在表头插入结点 void insertRear(const T&item);/在表尾添加结点 void insertAt(c
25、onst T&item);/在当前结点之前插入结点 void insertAfter(const T&item);/在当前结点之后插入结点 T deleteFront();/删除头结点 void deleteCurrent();/删除当前结点 T&data();/返回对当前结点成员数据的引用 const T&data()const;/返回对当前结点成员数据的常引用 /清空链表:释放所有结点的内存空间。被析构函数、operator=调用 void clear();template /生成新结点 Node*LinkedList:newNode(const T&item,Node*ptrNext)N
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C+语言程序设计进阶 5 C+ 语言程序设计 进阶
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内