C++程序设计 第7章 队列_第1页
C++程序设计 第7章 队列_第2页
C++程序设计 第7章 队列_第3页
C++程序设计 第7章 队列_第4页
C++程序设计 第7章 队列_第5页
已阅读5页,还剩84页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本周习题:

1.复习2.P263一.基本概念与知识自测题

3.继续本学期课堂作业的设计预习:第8章8.2、8.3、8.4、8.5第8章要求:(1)理解继承的概念,了解面向对象设计中继承和多态的合理性;(2)掌握派生类的构造与析构;(3)掌握在对象中使用类层次和继承思想进行设计、实现和测试;(4)理解多重继承,了解虚基类;(5)区别运行时的多态性的实现,理解重载与同名覆盖的差异;(6)理解虚函数与多态性;(7)实现运行时多态性的程序设计;7.3给单链表类模板增加两个成员函数:删除链表中所有数据域为指定值的节点和取出链表中第K个元素(从1开始计数)。template<typenameT>classList{ Node<T>*head,*tail;//链表头指针和尾指针public: List();//构造函数,生成头结点(空链表) ~List();//析构函数

……

voiddeleteall(Tdata);

int

Findk(intk);};template<typenameT>voidList<T>::deleteall(Tdata){

//严清洲

Node<T>*tempP=head->link;

for(;tempP!=NULL;tempP=tempP->link){

if(tempP->info==data){

DeleteNode(tempP); } }}template<typenameT>Node<T>*List<T>::Findk(intk){

inti; Node<T>*tempP=head->link;

for(i=1;i<k;i++){

tempP=tempP->link; }

cout<<“要找的节点数据为”<<tempP->info;//找到显示

returntempP;}

Node<int>*P1;List<int>list1,list2;

intk;

cin>>k;P1=list1.Findk(k);template<typenameT>TList<T>::Findk(intk){

inti; Node<T>*tempP=head->link;

for(i=1;i<k;i++){

tempP=tempP->link; } returntempP->info;}

List<int>list1,list2;

intk;

cin>>k;

cout<<list1.Findk(k);template<typenameT>classNode{//取出链表中第K个元素钱康

public:T&Getinfo();};template<typenameT>classList{public:Node<T>*GetNode(int);};template<typenameT>T&Node<T>::Getinfo(){returninfo;}template<typenameT>Node<T>*List<T>::GetNode(inti){Node<T>*TempP=head->link;

intj=1;

if(i<0)returnNULL;

if(i==0)returnhead;

while(TempP!=NULL&&j<i){

TempP=TempP->link;j++;}returnTempP;}Node<string>*n1;cout<<"要求寻找第几个节点?"<<endl;cin>>i;n1=list1.GetNode(i);if(n1!=NULL)

cout<<n1->Getinfo()<<endl;template<typenameT>voidList<T>::Reverse(){//宗袁月

Node<T>*tempP,*tempQ;

tempP=head->link; tail=head; head->link=NULL;

while(tempP!=NULL){

tempQ=tempP;

tempP=tempQ->link;

InsertFront(tempQ); }}template<typenameT>voidList<T>::InsertFront(Node<T>*p){ p->link=head->link; head->link=p;

if(tail==head)tail=p;}7.5试为单链表类模板设计一个将链表逆转的成员函数。要求不删除原结点,也不另建一个链表来取代,而是通过改变指针域的链接方向来逆转链表。template<typenameT>voidList<T>::turn(){

//郭明皓 Node<T>*tempP,*tempQ;

tempP=head->link; head->link=NULL;

while(tempP!=NULL){

tempQ=tempP;

tempP=tempP->link;

tempQ->link=head->link; head->link=tempQ; }}template<typenameT>Node<T>*List<T>::

Reverse(Node<T>*head){//方晗婧

if(head==NULL||head->link==NULL)//链表中没有元素或者只有一个元素

returnhead; Node<T>*tail=Reverse(head->link);//递归

head->link->link=head; head->link=NULL; returntail;//尾指针变为头指针}7.8修改顺序栈类,当栈满时,执行StackFull()操作;动态创建一个是原来的栈空间的两倍的空间,把原来栈中的内容放入新栈,再删除原栈空间。

template<typenameT>voidStack<T>::StackFull(){//陈愈杰

T*p=elements; elements=newT[2*maxSize];

for(inti=0;i<=maxSize;i++)elements[i]=p[i];

maxSize=2*maxSize;

delete[]p;}template<typenameT>voidStack<T>::Push(constT&data){

if(IsFull())StackFull();//栈满则扩大为2倍大小

elements[++top]=data;//栈顶指针先加1,元素再进栈,top是指向栈顶元素}7.3.3队列先进先出表——只允许在表的一端插入,在另一端删除。(先进先出------受限操作)a0a1a2…an-1…front元素移动方向rear出队:队头(front)进队:队尾(rear)队空队列中没有元素队满队列中元素个数达到上限一般状态队列中有元素,但未达到队满状态队列的基本状态a0a1an-1an……队头队尾入队出队数组下标

01n-1nmax(一般状态)元素移动方向

a0a1

an-1an

amax……队头队尾入队出队数组下标

01n-1nmax(队满状态)元素移动方向……队头队尾入队出队数组下标

01n-1nmax(队空状态)循环队列在想象中将数组弯曲成环形,元素出队时,后继元素不移动,每当队尾达到数组最后一个元素时,便再回到数组开头。只移动对头和对尾,数组中的元素不动1234……m-1m-2m-30amam+1am+2a3队头队尾a4am-2am-3am-1队满状态元素个数=m队尾1234……m-1m-2m-30a0a1a2a3队头一般状态1234……m-1m-2m-30队尾队头队空状态元素个数=0如何区分队列的空和满:当尾指针指向最后一个元素位置时(m-1),增加1,变为m,如何让对尾指针指向0(对头)?方法:用%m

取余得到根据元素个数元素个数=0时表示队列为空元素个数=m时表示队列满2.对尾+1=对头时表示队列满(队尾入队)对头+1=对尾时表示队列空(队头出队)【例7.10】循环队列顺序表类模板template<typename

T>classQueue{

int

rear,front; //队尾与队头

T*elements; //存放队列元素的容器

int

maxSize; //队列最多可容纳元素个数+1public:

Queue(int

ms=18);//建立队

~Queue(){delete[]elements;}

bool

IsEmpty()const{returnfront==rear;} //判队空

bool

IsFull()const{return(rear+1)%maxSize==front;}//判队满

int

Length()const{return(rear-front+maxSize)%maxSize;}

//求队中元素数,注意求余算法

void

EnQue(constT&info);//进队

TDeQue(); //出队

TGetFront(); //取队头数据

void

MakeEmpty(){front=rear=0;}//队置空(初始态)}; 【例7.10】循环队列顺序表类模板template<typenameT>Queue<T>::Queue(int

ms){

maxSize=ms;elements=new

T[maxSize];rear=front=0;assert(elements!=NULL);//分配成功}template<typenameT>voidQueue<T>::EnQue(const

T&info){//进队

assert(!IsFull());//队列不满,不满才能进队

rear=(rear+1)%maxSize;//队尾指针加1elements[rear]=data;//数据进队}【例7.10】循环队列顺序表类模板template<typenameT>TQueue<T>::DeQue(){//出队

assert(!IsEmpty());front=(front+1)%maxSize;//队头指针加1,注意front指向现在队头的前一位置

returnelements[front];//返回首元素}template<typenameT>TQueue<T>::GetFront(){//取对头数据

assert(!IsEmpty());

returnelements[(front+1)%maxSize];}【例7.10】循环队列顺序表类模板intmain(){

inti;Queue<char>que;//构造一新链队,缺省为18元素队列,可用17,包括串结束符

charstr1[]="abcdefghijklmnop";

que.MakeEmpty();//置队空

for(i=0;i<17;i++)que.EnQue(str1[i]);//入队

if(que.IsFull())cout<<“队满”;//判队满

cout<<“共有元素:”<<que.Length()<<endl;//队列中的元素个数

for(i=0;i<17;i++)cout<<que.DeQue();//出队

cout<<endl;

if(que.IsEmpty())cout<<"队空";

cout<<"共有元素:"<<que.Length()<<endl;return0;}链表结点类:template<typenameT>classNode{Tinfo;Node<T>*link;public:Node(Tinfo=0,Node*l=NULL);

friendclassQueue<T>;};template<typename

T>Node<T>::Node(Tinfo,Node*l){info=info;link=l;}【例7.11】链队类模板链队类模板:template<typenameT>classQueue{ Node<T>*front,*rear;public:Queue(){rear=front=NULL;}//构造一个空链队

~Queue();//析构函数

bool

IsEmpty(){returnfront==NULL;}//队空否?

void

EnQue(constT&info);//进队

TDeQue(); //出队

TGetFront(); //查看队头数据

void

MakeEmpty();//置空队列};【例7.11】链队类模板template<typenameT>voidQueue<T>::EnQue(constT&info){//进队

if(front==NULL)front=rear=newNode<T>(info,NULL);

else

rear=rear->link=newNode<T>(info,NULL);//尾节点指向下一个新创建节点}//链队向后生成template<typenameT>voidQueue<T>::MakeEmpty(){//置空队列

Node<T>*temp;

while(front!=NULL){temp=front;front=front->link;deletetemp;}}template<typenameT>Queue<T>::~Queue(){

MakeEmpty();//置空对列}【例7.11】链队类模板template<typenameT>TQueue<T>::DeQue(){//出队

assert(!IsEmpty());Node<T>*temp=front;Tinfo=temp->info; //取队头结点中的数据

front=front->link; //队头出队

deletetemp; //释放内存空间

returninfo;}template<typenameT>TQueue<T>::GetFront(){//查看队头数据

assert(!IsEmpty());//对空,结束程序

returnfront->info;}intmain(){

inti; Queue<char>que;//缺省为18元素队列,可用17,包括串结束符

charstr1[]="abcdefghijklmnop";

for(i=0;i<17;i++)que.EnQue(str1[i]);//入队

for(i=0;i<17;i++)cout<<que.DeQue();//出队

cout<<endl;

if(que.IsEmpty())cout<<“队空”<<endl;

return0;}【例7.11】链队类模板7.4.1

二叉树的概念

树(Tree)是由n(n≥0)个结点组成的有限集合。如n=0,称为空树。非空树有一个特定的结点,它只有直接后继,没有直接前驱,称之为根(root)。除根以外的其它结点划分为m(m≥0)个互不相交的有限集合T0,T1,……,Tm-1,每个集合又是一棵树,称为根的子树(subtree)。每棵子树的根结点有且仅有一个直接前驱,但可以有0个或多个直接后继。这是一个递归方法定义的数据结构。树的概念:7.4.1

二叉树的概念

ABCDFEGHJI…………0层……1层2层3层图7.18树的示意图根节点AA的子节点深度叶节点:

FGHIJ子树结点:包括数据项和多个指针项,指针项数目并不固定,且无次序。结点的度:结点所拥有的子树数量。叶结点:度为0的结点称叶节点,如:FGHIJ结点。分支结点:度≥1的结点。父节点、子结点:

若结点x的一棵树的根是y,则x称y的父节点,y称x的子结点。

(C是F的父节点,F是C的子节点)兄弟结点:同一父结点的多个节点互称为兄弟节点。结点的层次:从根到该结点所经路径上的分支条数。树的深度:树中结点的层次数(树的高度),例图7.18深度为4。树的度:树中结点度数的最大值。例图7.18:A、C、E、I

的度数分别为2、2、2、0,则数的度数为2。树的术语:7.4.1

二叉树的概念

二叉树(BinaryTree)是另一种独立的树形结构。二叉树是结点的一个有限集合,该集合或为空,或是由一个根结点及两棵树分别称为左子树和右子树的(注意有左右之分)互不相交的二叉树组成,其中左右子树分别可以为空子树或均为空树。这也是一个递归的定义。二叉树的特点是:每个结点最多两个孩子,并且子树有左右之分。二叉树的基本性质:

1.二叉树的第i层上最多有2i-1(i>=1)个结点;

2.深度为h的二叉树中最多有2h-1个结点;

3.在任一棵二叉树中,有n0叶子结点,有n2个度为2的结点,则有n0=n2+1。树的概念:7.4.1

二叉树的概念【例7.12】画出有三个结点的所有二叉树。解:结果见图7.19,共5种。图7.19

5种不同的三结点二叉树

满二叉树和完全二叉树:123456798101114131215图7.20满二叉树12345679810图7.21完全二叉树满二叉树:所有层的节点数都达到最大完全二叉树:除最后一层可能不满以外,其他各层都达到该层节点的最大数,最后一层如果不满,该层所有节点都全部靠左排。满二叉树肯定是完全二叉树

完全二叉树不一定是满二叉树7.4.2二叉树的遍历二叉树的遍历(binarytreetraversal):

遵从某种次序,查巡二叉树的所有结点,每个结点都被访问一次,而且仅访问一次。所谓“访问”指对结点施行某些操作,但不破坏它原来的数据结构。遍历二叉树有不同次序,规定先左后右,令L,R,V分别代表遍历一个结点的左右子树和访问该结点的操作,有三种方式:根节点左子树右子树VRL前序遍历的顺序为:VLR。每当遍历一个节点时就先处理该节点,之后先向左方前进,直到无法前进才往右方走。前序遍历(VLR):

先遍历根节点,再遍历左子树,最后遍历右子树。ABCFEDGHI例:先处理根节点A后,先往左子树经过B再到D,由于D没有左子树,故转向右子树G。再回到B,因为B没有右子树,所以此时A的左子树均遍历完毕,则转向A子树的右子树先到C,再往左边继续遍历,依次类推,可得到前序遍历的顺序为:ABDGCEHIF中序遍历(LVR):

先遍历左子树,再遍历根节点,最后才遍历右子树。根节点左子树右子树VRL中序遍历的顺序为:LVR。一开始先往左方向前进,直到无法前进才处理根节点,之后再往右方前进。ABCFEDGHI例:从节点A开始,一直往左走到D无法再前进,则处理D,再往D的右方到G。此时遍历完B左子树,接着处理B,再往B的右方前进。由于B没有右子树,故A的左子树遍历完毕,可处理节点A,再往A的右子树前进,依次类推,可得到中序遍历的顺序为:

DGBAHEICF后序遍历(LRV)

先遍历左子树,再遍历右子树,最后才遍历根节点。

根节点左子树右子树VRL后序遍历的顺序为:LRV。一开始先往左方向前进,直到无法前进才再往节点的右方前进,最后才处理根节点。ABCFEDGHI例:从节点A开始,一直往左走到D无法再前进,则往D的右方向前进到G,由于G没有左、右子树,故处理节点G。之后由于D的右子树遍历完毕,处理D,而B的左子树也相应地完成。且节点B没有右子树,处理B。此时节点A的左子树已遍历完毕,可往节点A的右子树经过C前进,依次类推,当节点A的右子树遍历完成,方可处理根节点A,得到后序遍历的顺序为:

GDBHIEFCA

7.4.2二叉树的遍历遍历实例:前序遍历访问次序为ABDEGCFH。

图7.23二叉树遍历

中序遍历结果为DBGEAFHC。后序遍历结果为DGEBHFCA。

7.4.2二叉树的遍历【例7.14】某二叉树先序遍历为ABCEFDGHIJK,中序遍历为ECFBDGAIHJK绘出该二叉树。

ABCDEFGHIJK图7.24例7.14二叉树按同样方法推出A的右子树。结果如图7.24。可以证明已知前序和中序访问次序可以唯一确定一棵二叉树。

解:由先序知A为根结点,而由中序知ECFBDG为左子树,IHJK为右子树。由前序中的BCEFDG知B为左子树根结点,由中序中的ECF

B

DG知ECF为其左子树,而DG为右子树。再由前序C

EF知C为左子树根结点,由中序E

C

F知E为C左子树,F为的右子树。再由前序D

G知,D为B的右子树根结点,由中序D

G知G为D的右子树。第八章继承与多态面向对象程序设计的三大技术特征——封装(encapsulation)继承(inheritance)多态(polymorphism)对象的概念(访问权限)继承——分层次认识,分层次设计,支持代码重用汽车卡车轿车共性特征个性特征多态——同一接口实现不同功能虚函数支持下的运行时多态(不同于重载)8.1继承与派生的概念

8.4虚基类

8.3多重继承与派生类成员标识

8.6多态性与虚函数

8.5派生类应用讨论

8.2派生类的构造函数与析构函数

本章内容8.1

继承与派生的概念继承机制——基于对对象(事物)的分层认识处理相似对象,简化描述,提高代码重用性几个名词——类派生(classderivation)技术基类(baseclass)或超类(superclass)派生类(derivedclass)或子类(subclass)举例说明派生的使用方法:classA{…};classB{…};//A、B称为基类classC:publicA,publicB{//C称为派生类

成员表1;//派生类特有的私有成员public:

成员表2;//派生类特有的公有成员protected:

成员表3;//派生类特有的保护成员};8.1.1类的派生与继承A对象成员B对象成员C对象成员继承自AC特有继承自B【例】由Student派生Student1类。classStudent{

intnum; charname[10]; charsex;public: voiddisplay();};classStudent1:publicStudent{

intage;char

addr[30];public:voiddisplay1();};voiddisplay1()派生类成员总构成

继承基类成员

改造基类成员

发展新成员重写构造函数与析构函数

——除构造与析构函数外,全盘接收基类成员,派生类中不需描述——与基类成员同名的成员,称为重构(override,覆盖)——定义自己特有的新成员,使派生类得以发展,具有个性

注意:1、同名覆盖不同于重载;

2、派生类不继承构造函数和析构函数,因此要重写。基类1基类2……基类n派生类1派生类2(a)多重继承

基类派生类1派生类2

(b)单继承

一个基类可以直接派生出多个派生类

派生类可继续派生新类,依此形成一个层次结构继承的方式多重继承(multiple-inheritance):有多个基类单一继承(single-inheritance):只有一个基类8.1.2公有派生与私有派生(1)公用派生基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有(不可直接访问)。(2)私有派生基类的公有成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有(不可直接访问)。(3)保护的派生基类的公有成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有(不可直接访问)。不能被外界引用,但可以被派生类的成员引用。不可直接访问

不可直接访问

private

不可直接访问

privateprotected不可直接访问

private

public私有派生

不可直接访问

不可直接访问

private不可直接访问

protectedprotected可直接访问

publicpublic公有派生

在派生类对象外访问派生类对象的基类成员

在派生类中对基类成员的访问限定基类中的访问限定派生方式

表8.1公有派生和私有派生的访问限定基类成员在派生类中的访问属性基类中的成员在公有派生类中的访问属性在私有派生类中的访问属性在保护派生类中的访问属性私有成员不可访问不可访问不可访问公有成员公有私有保护保护成员保护私有保护classStudent{//公有派生例

public://基类公用成员

voidget_value(){cin>>num>>name>>sex;}voiddisplay(){

cout<<″num:″<<num<<endl;

cout<<″name:″<<name<<endl;

cout<<″sex:″<<sex<<endl;}private://基类私有成员

intnum;stringname;charsex;};classStudent1:publicStudent{//派生类Student1public:

voidget_value1(){cin>>age>>addr;}voiddisplay1(){

cout<<″num:″<<num<<endl;

//错误

cout<<″name:″<<name<<endl;

//错误

cout<<″sex:″<<sex<<endl;

//错误

cout<<″age:″<<age<<endl;//正确

cout<<″address:″<<addr<<endl;//正确

}private:

intage;stringaddr;};display();//调用基类公有函数问题:若要在派生类display1();中输出5个数据。程序如何修改?intmain(){Student1stud;//定义派生类Student1的对象stud

stud.get_value();

stud.

get_value1();

stud.display();

//调用基类的公用成员函数,输出基类中3个数据成员的值

stud.display1();

//调用派生类的公用成员函数,输出派生类中两个数据成员的值

return0;}

相当于基类A的私有成员k不可见私有派生例私有基类的私有成员按规定只能被基类的成员函数引用,在基类外不能访问,因此它们在派生类中是隐蔽的,不可访问的。对于不需要再往下继承的类的功能可以用私有继承方式把它隐蔽起来,这样,下一层的派生类无法访问它的任何成员。与私有成员不同,保护成员可以被派生类的成员函数引用。保护派生例protected成员的特点与作用:对建立其所在类对象的模块来说(水平访问时),它与private成员的性质相同。对于其派生类来说(垂直访问时),它与

public成员的性质相同。既实现了数据隐藏,又方便继承,实现代码重用。例:

classA{protected:

intx;};

intmain(){Aa;

a.x=5;//错误,不能在类外访问}该情况下,保护成员和私有成员一样得到了很好的隐藏。例:

classA{protected:

intx;}classB:publicA{//公有派生

public:voidFunction();};voidB::Function(){X=5;//正确,可以被派生类的成员访问}在派生类中,成员有4种不同的访问属性:派生类中的成员在派生类中在派生类外在下层公用派生类中派生类中访问属性为公有的成员可以可以可以派生类中访问属性为保护的成员可以不可以可以派生类中访问属性为私有的成员可以不可以不可以派生类中不可访问的成员不可以不可以不可以派生类构造函数的定义形式为:C::C(参数总表):A(参数表1),B(参数表2){

//派生类新增成员的初始化;}8.2派生类的构造函数与析构函数派生类对象初始化的内容应包含继承来的成员自己的成员——调用基类构造函数对于如下派生体系:classA{};classB{};classC:publicA,publicB{};1、先调用基类构造函数初始化继承的成员2、调用顺序只与继承顺序相关派生类构造函数执行次序:

首先执行基类构造函数,然后执行

派生类的构造函数。注意:

在派生类构造函数中,只要基类不是使用缺省构造函数都要显式给出基类名和参数表。如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的缺省构造函数。如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数。例:#include<iostream.h>classA{

intx;protected:

inty;public:

intz;

A(int

a,int

b,intc){x=a;y=b;z=c;}voidSetx(inta){x=a;}voidSety(inta){y=a;}

int

Getx(){returnx;}

int

Gety(){returny;}voidShowA(){cout<<"x="<<x<<'\t'<<"y="<<y<<'\t'<<"z="<<z<<'\n';}};classB:publicA{

int

u,v;public:

B(int

a,int

b,int

c,int

d,int

e):A(a,b,c){u=d;v=e; }voidShowB(){

cout<<u<<'\t'<<v<<'\n';

cout<<Getx()<<'\t'<<y<<'\t'<<z<<'\n'; }

intSum(){return(Getx()+y+z+u+v); }};voidmain(){Bb1(1,2,3,4,5);b1.ShowA(); b1.ShowB();

cout<<"Sum="<<b1.Sum()<<'\n';

cout<<"y="<<b1.Gety()<<'\t';

cout<<"z="<<b1.z<<'\n'; }输出:1 2 34 51 2 3Sum=15y=2 z=3复杂对象构造的顺序:classA{};classB{};ClassC:publicB,publicA{Bb1,b2;

intx;pubic:C(……):B(…),A(…),b1(…),b2(…){

x=…;}……;};派生类构造函数各部分的执行次序为:1.调用基类构造函数,按它们在派生类声明的先后顺序,依次调用。2.调用新增成员对象的构造函数,按它们在类定义中声明的先后顺序,依次调用。3.派生类的构造函数体中的操作。C(……):A(…),B(…),b2(…),b1(…){

x=…;}析构函数:析构函数的功能是作善后工作。只要在函数体内把派生类新增一般成员处理好就可以了,对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成。

析构函数各部分执行次序与构造函数相反,首先对派生类新增一般成员析构,然后对新增对象成员析构,最后对基类成员析构。例:#include<iostream.h>classB{public: B();

B(inti); ~B(); voidPrint();private:

intb;};B::B(){ b=0;

cout<<“B的无参构造函数调用."<<endl;}B::B(inti){ b=i;

cout<<“B的有参构造函数调用."<<endl;}B::~B(){

cout<<“B的析构函数调用."<<endl;}voidB::Print(){

cout<<b<<endl;}classC:publicB{public:C();

C(int

i,intj); ~C(); voidPrint();private:

intc;};C::C(){ c=0;

cout<<"C的无参构造函数调用."<<endl;}C::C(int

i,intj):B(i){ c=j;

cout<<“C的有参构造函数调用."<<endl;}C::~C(){

cout<<“C的析构函数调用."<<endl;}C::C():B(){voidC::Print(){ B::Print();//调用基类函数

cout<<c<<endl;}intmain(){ Cobj(5,6);

obj.Print(); return0;}输出:B的有参构造函数调用.C的有参构造函数调用.56C的析构函数调用.B的析构函数调用.【例8.1】由在册人员类公有派生学生类。希望基类和派生类共享相同的公有接口,所以采用公有派生来实现。基类:classPerson{ stringIdPerson; //身份证号,18位数字

stringName; //姓名

TsexSex;//性别enum

Tsex{man,woman};

intBirthday; //生日,格式1986年8月18日写作19860818 stringHomeAddress; //家庭地址public:

Person(string,string,Tsex,int,string);//构造函数

Person();//缺省的构造函数

~Person();//析构函数

voidSetName(string)){Name=name;}

//修改名字

stringGetName(){returnName;}

//提取名字

void

SetSex(Tsexsex){Sex=sex;}

//修改性别

Tsex

GetSex(){returnSex;}

//提取性别

void

SetId(stringid){IdPerson=id;}

//修改身份证号

stringGetId(){return

IdPerson;}

//提取身份证号

void

SetBirth(int

birthday){Birthday=birthday;}

//修改生日

int

GetBirth(){returnBirthday;}

//提取生日

voidSetHomeAdd(string){HomeAddress=homeadd;

}

//修改住址

stringGetHomeAdd(){returnHomeAddress;}

//提取住址

voidPrintPersonInfo();

//输出个人信息};接口函数:派生的学生类:classStudent:publicPerson{//定义派生的学生类

stringNoStudent;//学号

coursecs[30];//30门课程与成绩public:

Student(stringid,stringname,Tsex

sex,intbirthday,stringhomeadd,stringnostud);

//注意派生类构造函数声明方式

Student();

//缺省派生类构造函数

~Student();//派生类析构函数

SetCourse(string,int);//课程设置

int

GetCourse(string);//查找成绩

void

PrintStudentInfo();//打印学生情况};struct

course{stringcoursename;

intgrade;};主函数Person::Person(stringid,stringname,Tsex,intbirthday,stringhomeadd){

IdPerson=id; Name=name; Sex=sex; Birthday=birthday;

HomeAddress=homeadd;}构造函数:Person::Person(){

IdPerson="#";Name="#";Sex=mid; Birthday=0;HomeAddress="#";}无参构造函数:析构函数:Person::~Person(){}//string内部动态数组的释放,由string自带的析构函数完成voidPerson::PrintPersonInfo(){

inti;

cout<<"身份证号:"<<IdPerson<<'\n'<<"姓名:"<<Name<<'\n'<<"性别:";

if(Sex==man)cout<<"男"<<'\n';

else

if(Sex==woman)cout<<"女"<<'\n';

else

cout<<""<<'\n';

cout<<"出生年月日:"; i=Birthday;

cout<<i/10000<<"年"; i=i%10000;

cout<<i/100<<"月"<<i%100<<"日"<<'\n‘<<"家庭住址:"<<HomeAddress<<'\n';}输出个人信息:Student::Student(stringid,stringname,Tsex

sex,intbirthday,stringhomeadd,stringnostud):Person(id,name,sex,birthday,homeadd){//注意Person参数表不用类型

NoStudent=nostud;

for(inti=0;i<30;i++){//课程与成绩清空

cs[i].coursename="#";

cs[i].grade=0; }}派生类构造函数:Student::Student(){

//基类缺省的无参数构造函数不必显式给出

int

i;

NoStudent="";

for(i=0;i<30;i++){

//课程与成绩清零,将来由键盘输入

cs[i].coursename="";

cs[i].grade=0; }}Student::~Student(){}

//基类析构函数以及成员对象析构函数自动调用派生类构造函数:派生类析构函数:int

Student::SetCourse(string

coursename,intgrade){

boolb=false;//标识新输入的课程,还是更新成绩

int

i;

for(i=0;i<30;i++){

if(cs[i].coursename=="#"){

//判表是否进入未使用部分(如有对应删除,应按顺序表方式)

cs[i].coursename=coursename;

cs[i].grade=grade; b=false;break;}

else

if(cs[i].coursename==coursename){

//是否已有该课程记录

cs[i].grade=grade;b=true;break;}}

if(i==30)return0;//成绩表满返回0

if(b)return1;//修改成绩返回1

elsereturn2;//登记成绩返回2}学生类课程设置函数:int

Student::GetCourse(string

coursename){

inti;

for(i=0;i<30;i++)

if(cs[i].coursename==coursename)

return

cs[i].grade;return-1;//找到返回成绩,未找到返回-1}查找学生课程成绩函数:void

Student::PrintStudentInfo(){

inti;

cout<<"学号:"<<NoStudent<<'\n';

PrintPersonInfo();

for(i=0;i<30;i++)//打印各科成绩

if(cs[i].coursename!="#")

cout<<cs[i].coursename<<'\t'<<cs[i].grade<<'\n';

else

break;

cout<<"--------完--------"<<endl;}打印学生情况函数:例8.1主函数:intmain(){

chartemp[30];

int

i,k;Personper1("320102820818161","沈俊",man,19820818

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论