ImageVerifierCode 换一换
格式:PPT , 页数:102 ,大小:595.50KB ,
资源ID:13361991      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/13361991.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(第八章第二版.ppt)为本站上传会员【pc****0】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

第八章第二版.ppt

1、单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,继承,(inheritance),:,该机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。,体现了由简单到复杂的认识过程,。,第八章 继承与多态,多态性,(polymorphism):,多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于编译时的多态性。以虚函数为基础的运行时的多态性是面向对象程序设计的标志性特征。,体现了类推和比喻

2、的思想方法。,第八章 继承与多态,8.1,继承与派生的概念,8.4,虚基类 (选读),8.3,多重继承与派生类成员标识,8.6,多态性与虚函数,8.5,派生类应用讨论,8.2,派生类的构造函数与析构函数,8.1,继承与派生的概念,层次概念,是计算机的重要概念。通过,继承,(,inheritance,)的机制可对类(,class,),分层,提供类型,/,子类型的关系。,C+,通过,类派生,(,class derivation,),的机制来支持继承。被继承的类称为,基类,(,base class,),或,超类,(,superclass,),,新的类为,派生类,(,derived class,),或

3、子类,(,subclass,)。,基类和派生类的集合称作,类继承层次结构,(,hierarchy,)。,如果基类和派生类共享相同的公有接口,则派生类被称作基类的子类型(,subtype,)。,层次概念:,派生反映了事物之间的联系,事物的共性与个性之间的关系。派生与独立设计若干相关的类,前者工作量少,重复的部分可以从基类继承来,不需要单独,编程,。,8.1,继承与派生的概念,8.1.1,类的派生与继承,8.1.2,公有派生与私有派生,派生类的定义:,class,派生类名:访问限定符 基类名,1,,访问限定符,基类名,2,,,,访问限定符 基类名,n,private,:,成员表,1,;,/,派生

4、类增加或替代的私有成员,public,:,成员表,2,;,/,派生类增加或替代的公有成员,protected,:,成员表,3,;,/,派生类增加或替代的保护成员,;,/,分号不可少,其中基类,1,,基类,2,,,是已声明的类。,在派生类定义的类体中给出的成员称为,派生类成员,,它们是新增加成员,它们给派生类添加了不同于基类的新的属性和功能。派生类成员也包括取代基类成员的更新成员。,8.1.1,类的派生与继承,基类,1,基类,2,基类,n,派生类,1,派生类,2,基类,派生类,1,派生类,2,(,a,),多重继承,(,b,),单继承,图,8.1,多重继承与单继承,一个基类可以直接派生出多个派生类

5、派生类可以由多个基类共同派生出来,称多重继承。,8.1.1,类的派生与继承,多重继承:,如果一个派生类可以同时有多个基类,称为多重继承(,multiple-inheritance,),这时的派生类同时得到了多个已有类的特征。,单继承:,派生类只有一个直接基类的情况称为单继承(,single-inheritance,)。,8.1.1,类的派生与继承,在派生过程中,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个层次结构。直接参与派生出某类称为直接基类,而基类的基类,以及更深层的基类称为,间接基类,。,类族:,同时一个基类可以直接派生出多个派生类。这样形成了一个相互关联的类族

6、如,MFC,就是这样的族类,它由一个,CObject,类派生出,200,个,MFC,类中的绝大多数。,多层次继承:,编制派生类时可分四步,吸收基类的成员,改造基类成员,发展新成员,重写构造函数与析构函数,8.1.1,类的派生与继承,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收,声明一个和某基类成员同名的新成员,派生类中的新成员就屏蔽了基类同名成员称为同名覆盖(,override,),派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。,派生编程步骤:,8.1.1,类的派生与继承,第二步中,,新成员如是成员函数,参数表也必须一样,,否则是重载。,第三步中,独有

7、的新成员才是继承与派生的核心特征。,第四步是重写构造函数与析构函数,派生类不继承这两种函数。不管原来的函数是否可用,一律重写可免出错,。,访问控制:,亦称为,继承方式,,是对基类成员进一步的限制。访问控制也是三种:,公有(,public,),方式,亦称公有继承,保护(,protected,)方式,亦称保护继承,私有(,private,),方式,亦称私有继承。,8.1.2,公有派生与私有派生,不可直接访问,不可直接访问,private,不可直接访问,private,protected,不可直接访问,private,public,私有派生,不可直接访问,不可直接访问,private,不可直接访问,

8、protected,protected,可直接访问,public,public,公有派生,在派生类对象外访问派生类对象的基类成员,在派生类中对基类成员的访问限定,基类中的访问限定,派生方式,访问限定符两方面含义:,派生类成员(新增成员)函数对基类(继承来的)成员的访问(调用和操作),,和,从派生类对象之外对派生类对象中的基类成员的访问,。,公有派生是绝对主流,。,派生类构造函数的定义:,派生类名,:,派生类名(参数总表),:,基类名,1,(参数名表,1,),,基类名,2,(参数名表,2,),,,基类名,n,(参数名表,n,),,,成员对象名,1,(成员对象参数名表,1,),,,成员对象名,m,

9、成员对象参数名表,m,),/,派生类新增成员的初始化;,/,所列出的成员对象名全部为新增成员对象的名字,注意:,在构造函数的声明中,冒号及冒号以后部分必须略去。,所谓不能继承并不是不能利用,而是把基类的构造函数作为新的构造函数的一部分,或者讲调用基类的构造函数。,基类名仅指直接基类,写了底层基类,编译器认为出错,。,冒号后的基类名,成员对象名的次序可以随意,这里的次序与调用次序无关。,8.2,派生类的构造函数与析构函数,派生类构造函数各部分执行次序:,1.,调用基类构造函数,按它们在派生类定义的先后顺序,顺序调用。,2.,调用成员对象的构造函数,按它们在类定义中声明的先后顺序,顺序调用。,3

10、派生类的构造函数体中的操作。,8.2,派生类的构造函数与析构函数,注意:,在派生类构造函数中,只要基类不是使用无参的默认构造函数都要显式给出基类名和参数表,。,如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。,如果基类定义了带有形参表的构造函数时,派生类就应当定义构造函数。,8.2,派生类的构造函数与析构函数,析构函数:,析构函数,的功能是作善后工作。,只要在函数体内把派生类新增一般成员处理好就可以了,,而,对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成,。,析构函数各部分执行次序与构造函数相反,,首先对派生类新增一般成员析构

11、然后对新增对象成员析构,最后对基类成员析构,。,【,例,8.1】,由在册人员类公有派生学生类,【,例,8.1】,由在册人员类公有派生学生类。我们希望基类和派生类共享相同的公有接口,只能采用公有派生来实现。,基类:,class,Person,string,IdPerson,;,/,身份证号,18,位数字,string Name;,/,姓名,Tsex,Sex;,/,性别,enum,Tsexmid,man,woman,;,int,Birthday;,/,生日,格式,1986,年,8,月,18,日写作,19860818,string,HomeAddress,;,/,家庭地址,public:,Pers

12、on(string,string,Tsex,int,string);,/,构造函数,Person();,/,默认的构造函数,Person();,/,析构函数,【,例,8.1】,由在册人员类公有派生学生类,void,SetName(string,);,/,修改名字,string,GetName(),return,Name;,/,提取名字,void,SetSex(Tsex,sex)Sex,=sex;,/,修改性别,Tsex,GetSex(),return,Sex;,/,提取性别,void,SetId(string,id)IdPerson,=id;,/,修改身份证号,string,GetId(),r

13、eturn,IdPerson,;,/,提取身份证号,void,SetBirth(,int,birthday)Birthday,=birthday;,/,修改生日,int,GetBirth(),return,Birthday;,/,提取生日,void,SetHomeAdd(string,);,/,修改住址,string,GetHomeAdd(),return,HomeAddress,;,/,提取住址,void,PrintPersonInfo,();,/,输出个人信息,;,/,接口函数:,【,例,8.1】,由在册人员类公有派生学生类,派生的学生类,:,class,Student:,public,P

14、erson,/,定义派生的学生类,string,NoStudent,;,/,学号,course cs30;,/30,门课程与成绩,public,:,Student(string,id,string,name,Tsex,sex,int,birthday,string,homeadd,string,nostud,);,/,注意,派生类构造函数,声明方式,Student();,/,默认派生类构造函数,Student();,/,派生类析构函数,SetCourse(string,int,);,/,课程设置,int,GetCourse(string,);,/,查找成绩,void,PrintStudentI

15、nfo,();,/,打印学生情况,;,struct,course,string,coursename,;,int,grade;,验证,主函数,8.2,派生类的构造函数与析构函数,注意:,本例中标准,C+,字符串,string,是作为成员对象使用的(,聚合,),动态内存分配的构造和析构被封装起来,使用十分简单。如使用动态生成的,C,风格字符串,要考虑深复制,那要复杂得多。,提倡完善的类对象封装,不仅封装数据和对数据的操作,而且封装资源的动态分配与释放,形成一个完备的子系统。在一个有层次结构的类体系中资源的动态分配与释放应封装在成员对象中,,如同使用标准的,string,字符串类那样。,聚合是一种

16、完善的封装。采用成员对象将大大简化层次结构的类体系中资源的动态分配与释放的处理方法,不再出现难度极大的多层次的深复制。,8.3,多重继承与派生类成员标识(选读),由多个基类共同派生出新的派生类,这样的继承结构被称为多重继承或多继承(,multiple-inheritance,),椅子,床,沙发,(,单继承,),躺椅,(,多重继承,),两用沙发,(,多重继承,),图,8.2,椅子,床到两用沙发,多重继承实例:,在册人员,学生,(,单继承,),教职工,(,单继承,),兼职教师,(,单继承,),教师,(,单继承,),行政人员,(,单继承,),工人,(,单继承,),研究生,(,单继承,),行政人员兼教

17、师,(,多重继承,),在职研究生,(,多重继承,),研究生助教,(,多重继承,),图,8.3,大学在册人员继承关系,8.3,多重继承与派生类成员标识(选读),派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个,层次结构,。,8.3,多重继承与派生类成员标识(选读),歧义性问题,:,参见图,8.3,,比如行政人员兼教师,在其基类教师中有一个“教职工编号”,另一基类行政人员中也有一个“教职工编号”,如果只讲教职工编号那么是哪一个基类中的呢?这两者可能是一回事,但,计算机系统并不这么认为,。,进一步,如果“教职工编号”是由两个基类“教师”和“行政人员”共同的基类“教职工”类继承来的

18、只有同一个标识符,也不能用改标识符来区分。,唯一标识问题:,通常采用作用域分辨符“,:”,:,基类名,:,成员名,;,/,数据成员,基类名,:,成员名(参数表),;,/,函数成员,class EGStudent,int,No,在职学号,class GStudent,int,No,研究生号,.,class Student,int,No,学生号,.,class Person,int,No,身份证号,.,class Employee,int,No,工作证号,.,class Person,int,No,身份证号,.,图,8.4,(,a,)在职研究生派生类关系,定义,EGStudent,类对象,EGS

19、tudent1,,并假定派生全部为公有派生,,而,int,No,全为公有成员,:,EGStud1.No,/,在职学号,EGStud1.GStudent:No,/,研究生号,EGStud1.GStudent.Student:No,/,学生号,EGStud1.GStudent.Student.,Person:No,/,身份证号,EGStud1.Employee,:,No,/,工作证号,EGStud1.Employee.Person:No,/,身份证号,两个身份证号从逻辑上讲应是一回事,但是物理上是分配了不同内存空间,是两个变量,请参见图,8.4(b),。,Person,Person,Student

20、Employee,GStudent,EGStudent,Person,成员,Person,成员,Student,新成员,GStudent,新成员,Employee,新成员,EGStudent,新成员,图,8.4,(,b,)在职研究生派生类存储图,建议采用有确定字面意思的标识符,它可以被编译器简单区分出来。,如果,class Person,的身份证号标识为,int,IdPerson,,则写为:,EGStud1.GStudent:IdPerson,EGStud1.Employee:IdPerson,不必标出那么多层次的类,但写,EGStud1.IdPerson,是错的。,作用域分辨符不能嵌套使用

21、如:,EGStud1.GStudent:Student:No,/,学生号,EGStud1.GStudent:Student:Person:No,/,身份证号,是,错误,的。,8.3,多重继承与派生类成员标识(选读),8.3,多重继承与派生类成员标识(选读),一般数据成员总是私有成员,派生类对基类的访问只能间接进行。访问身份证号,应通过,class Person,中的公有成员函数(接口),GetNo,(),和,SetNo,(),进行:,EGStud1.Employee.Person:,SetNo(int no),;,no=EGStud1.Employee.Person:,GetNo(),;,

22、注意:,【,例,8.2】,由圆和高多重继承派生出圆锥。,因为公有派生时,在派生类中不可以直接访问基类的私有成员,但,可以直接访问基类的保护成员,,当需要在派生类中访问基类的数据成员时,可以将它们定义为保护的,而不是私有的。,本例中类,Circle,为圆;类,Line,为高;类,Cone,为圆锥,由,Circle,和,Line,公有派生而来。在,Cone,类中,,Circle,和,Line,类的接口完全不变,可以直接调用,这就是公有派生的优点。在,Cone,的成员函数中可直接访问,Circle,和,Line,中的公有成员和保护成员。,【,例,8.2】,由圆和高多重继承派生出圆锥,检证,主程序:,

23、圆类,Circle,定义,高类,Line,定义,圆锥类,Cone,定义,虚基类的引入:,在图,8.4,中,两个身份证号显然是不合理的。可以把,class,Person,这个共同基类设置为,虚基类,,这样就仅有一个,Person,基类成员,从不同路径继承来的同名数据成员(,身份证号,)在内存中就是同一个数据。,8.4,虚基类(选读),注意:,virtual,关键字只对紧随其后的基类名起作用,:,class,Student:,virtual,public,Person.;,class,Employee:,virtual,public,Person.;,虚基类,(virtual base class

24、),定义:,class,派生类名,:,virtual,访问限定符 基类类名,.;,class,派生类名,:,访问限定符,virtual,基类类名,.;,8.4,虚基类(选读),图,8.5,采用虚基类后在职研究生类储存图,Student,GStudent,EGStudent,Person,Student,新成员,GStudent,新成员,Person,Employee,新成员,Person,成员,EGStudent,新成员,Person,Person,Employee,这种继承称为虚拟继承,虚拟继承:,在,Person,的位置上放的是指针,,,两个指针都指向,Person,成员存储的内存,。这种

25、继承称为,虚拟继承,(,virtual inheritance,)。,8.4,虚基类(选读),派生类名,:,派生类名,(,参数总表,):,基类名,1(,参数名表,1),基类名,2(,参数名表,2),基类名,n(,参数名表,n),成员对象名,1(,成员对象参数名表,1),成员对象名,m(,成员对象参数名表,m),,,底层虚基类名,1(,参数名表,1),底层虚基类名,r(,参数名表,r),/,派生类新增成员的初始化,;,/,所列出的成员对象名全部为新增成员对象的名字,在多层虚拟继承构造函数中,基类名不仅要列出直接基类,而且要列出底层虚基类,否则编译器认为出错。,虚拟继承的构造函数:,8.4,虚基类

26、选读),在派生类对象的,创建,中:,首先是虚基类的构造函数并按它们声明的顺序构造。,第二批是非虚基类的构造函数按它们声明的顺序调用。,第三批是成员对象的构造函数。,最后是派生类自己的构造函数被调用。,构造函数执行次序:,8.4,虚基类(选读),【,例,8.3】,在采用虚基类的多重继承中,构造与析构的次序。,class,Dclass:,public,Bclass1,virtual,Bclass3,virtual Bclass2,Object,object,;,public,:,Dclass():object(),Bclass2(),Bclass3(),Bclass1(),cout,派生类建立,

27、n;,Dclass()cout,派生类析构,!n;,;,int,main(),Dclass,dd,;,cout,PrintStudentInfo,();,per4=stu4;,delete per4;,/,用基类指针撤销派生类,动态生成的对象必须显式撤销,8.6.1,虚函数的定义,在主函数中添加以下内容:,通过在析构函数中加显示语句发现先调,Student,析构函数,后调,Person,析构函数。,这里再次强调,动态生成的对象必须显式撤销,。,纯虚函数:,纯虚函数,(,pure virtual function,)是指被标明为不具体实现的虚拟成员函数。它用于这样的情况:定义一个基类时,会遇到

28、无法定义基类中虚函数的具体实现,其实现依赖于不同的派生类。,8.6.2,纯虚函数,纯虚函数的定义:,virtual,返回类型 函数名(参数表),=0,;,含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有实现部分,不能产生对象,所以含有纯虚函数的类是,抽象类,。,1,定义纯虚函数时,不能定义虚函数的实现部分。即使是函数体为空也不可以,函数体为空就可以执行,只是什么也不做就返回。而纯虚函数不能调用。,2 “=0”,表明程序员将不定义该函数,函数声明是为派生类保留一个位置。,“,=0”,本质上是将指向函数体的指针定为,NULL,。,3,在派生类中必须有重新定义的纯虚函数的函数体,这样的派生类才能

29、用来定义对象。,8.6.2,纯虚函数,定义纯虚函数的要点:,【,例,8.8】,学校对在册人员进行奖励,依据是业绩分,但是,业绩分的计算方法只能对具体人员进行,,如学生,教师,行政人员,工人,算法都不同,所以可以将在册人员类作为一个抽象类,,业绩计算方法作为一个纯虚函数,。,在主函数中全部用指向基类的指针来调用,8.6.2,纯虚函数,业绩分,基类定义,业绩分,学生派生类定义,业绩分,教师派生类定义,验证,主函数,【,例,8.9】,用,虚函数,来实现,辛普生,法求函数的定积分。,8.6.2,纯虚函数,纯虚,函数实现,通用算法,:,辛普生法求,定积分类,在派生类中加,被积函数,:,验证,主函数,8.

30、6.3,继承与多态的应用,单链表派生类(选读),【,例,8.10】,通用单链表派生类,。,第一步,改造,【,例,7.4,】,的头文件,不,采用模板类,而采用虚函数实现多态性,达到通用的目的,。结点类数据域被改造为指针,而把数据放在一个抽象类中,由指针与之建立联系。,数据域,(指向抽象,数据类的指,针),由抽象类派,生的数据类,对象(如串,对象),指针域(指,向下一结,点),结点类对象,动态建立的,数据类对象,图,8.9,结点构造,class,Object,/,数据类为抽象类,public:,Object(),virtual,bool,operator,(Object,/,纯虚函数,参数必须为引

31、用或指针,virtual,bool,operator,!=(Object,/,纯虚函数,参数必须为引用或指针,virtual void,Print()=0;,/,纯虚函数,virtual,Object();,/,析构函数可为虚函数,构造函数不行,8.6.3,继承与多态的应用,单链表派生类(选读),结点组织,采用结点类加数据类,数据类定义,:,本题要点:,采用虚函数实现多态性,达到通用的目的。,堆内存的分配与释放,关键不是创建,而是释放!,说明:,数据抽象类中含有三个纯虚函数:输出函数和两个比较函数。当抽象类在派生时重新定义三个纯虚函数,可以进行各种类型,包括类和结构对象的比较和输出,。,本例介

32、绍程序总体组成为主,链表的操作由学生自己,仔细,阅读。,8.6.3,继承与多态的应用,单链表派生类(选读),抽象类中的,析构函数也是虚函数,这一点非常重要,当抽象类派生的数据类的数据部分是动态产生的,而由结点类删除释放数据类对象时,必须由数据类的析构函数来释放该类对象数据部分占用的动态分配的内存,。这时必须重新定义析构函数。,Class,Node,O,bject*info;,/,数据域用指针指向数据类对象,Node*link;,/,指针域,public,:,Node();,/,生成头结点的,构造函数,Node(),;,/,析构函数,void,InsertAfter(Node,*P);,/,在当

33、前结点后插入一个结点,Node*,RemoveAfter,();,/,删除当前结点的后继结点,,返回该结点备用,void,Linkinfo(Object,*,obj,);,/,把,数据对象连接到结点,friend class,List;,/,以,List,为友元类,,List,可直接访问,Node,的私有函数,,;,8.6.3,继承与多态的应用,单链表派生类(选读),结点类定义,:,class,List,Node*head,*tail;,/,链表头指针和尾指针,public,:,List();,/,构造函数,,生成头结点,(,空链表,),List();,/,析构函数,void,MakeEmpt

34、y,();,/,清空链表,,只余表头结点,Node*,Find(Object,&,obj,);,/,搜索数据域与定值相同的结点,,返回该结点的地址,int,Length();,/,计算单链表长度,void,PrintList,();,/,打印链表的数据域,void,InsertFront(Node,*p);,/,可用来向前生成链表,void,InsertRear(Node,*p);,/,可用来向后生成链表,void,InsertOrder(Node,*p);,/,按,升序生成链表,Node*,CreatNode,();,/,创建一个结点,(,孤立结点,),Node*,DeleteNode(No

35、de,*p);,/,删除指定结点,8.6.3,继承与多态的应用,单链表派生类(选读),链表类,定义:,第二步,,,取代模板定义泛型类型为具体类型(包括类)的步骤是,由抽象类派生数据类,。数据类的数据采用字符类串,string,,动态分配和释放内存都在,string,类中完成。为了完成数据类的比较和输出,超载了比较运算符和输出函数(虚函数)。数据类的比较实际是字符串,string,的比较。,8.6.3,继承与多态的应用,单链表派生类(选读),class,StringObject:,public,Object,string,sptr,;,public,:,StringObject,(),sptr,

36、StringObject(string,s)sptr,=s;,StringObject,();,/,析构函数,bool,operator,(Object,/,大于函数,bool,operator,!=(Object,/,不等于函数,void,Print();,/,打印函数,;,验证,主函数,运行结果,分析与比较:,在该程序中,特别要仔细揣摩堆内存的分配与释放。删除一个结点时系统自动调用结点类析构函数释放结点占用的动态内存,而结点类析构函数自动调用数据域类虚析构函数,数据域类析构函数自动调用,string,类的析构函数释放所占用的动态内存。一环套一环,一步都不能错。这是使用动态内存分配的关

37、键。即,关键不是创建,而是释放,!,运行时的多态性需要维护一个动态指针表才能正确指向各相关类中的同名虚函数。所以多态与模板比较,模板的效率更高,标准模板库中用容器来泛型化数据结构中的许多算法。对数据结构的使用当然借助模板库。多态不适用于性能要求很高的实时应用程序,但继承与多态可用与其它更多方面,每一种技术都有可以充分发挥自己能力的地方。,8.6.3,继承与多态的应用,单链表派生类(选读),动态绑定(,dynamic binding,),亦称滞后绑定(,late binding,),,对应于,静态绑定(,static binding,),。,如果使用对象名和点成员选择运算符,“,.,”,引用特定

38、的一个对象来调用虚函数,则被调用的虚函数是在编译时确定的(称为,静态绑定,),如果使用基类指针或引用指明派生类对象并使用该指针调用虚函数(成员选择符用箭头号“,-”,),则程序动态地(运行时)选择该派生类的虚函数,称为,动态绑定,。,8.6.4,动态绑定(选读),绑定是指计算机程序自身彼此关联的过程,是把一个标识符名和一个存储地址联系在一起的过程,也就是把一条消息和一个对象的操作相结合的过程,。,图,8.9,虚函数调用的控制流程,“,dog,”,StringObject,动态无名对象,StringObject,动态无名对象,“,cat,”,指向,Object,类指针,指向结点类指针,指向,Ob

39、ject,类指针,指向结点类指针,指向,Object,类指针,指向结点类指针,StringObject,动态无名对象,“,cock,”,析构函数指针,0,比较函数指针,0,输出函数指针,StringObject,虚函数表,抽象类,Object,虚函数表,析构函数指针,比较函数指针,输出函数指针,ComplexObject,虚函数,析构函数指针,比较函数指针,输出函数指针,默认析构函数,释放动态串析构函数,串比较函数,打印串函数,默认析构,函数,复数模大小比较函数,打印复数函数,8.6.4,动态绑定(选读),C+,编译器编译含有一个或几个虚函数的类及 其派生类时,对该类建立,虚函数表(,Virt

40、ual function table,,,vtable,),。虚函数表使执行程序正确选择每次执行时应使用的虚函数。,多态是由复杂的数据结构实现的,参见图,8.10,。图,8.10,是以,【,例,8.10】,为基础的,不过增加了一个由抽象类,Object,派生的复数数据类,ComplexObject,。,图中列出了基类和各派生类的虚函数表,这些表是由指向函数的指针组成的,。,8.6.4,动态绑定(选读),还有第二层指针,在实例化带虚函数的类(创建对象)时,编译器,在对象前加上一个指向该类的虚函数表的指针,。,第三层指针是链表结点类对象中,指向抽象基类,Object,的指针,(这也可以是引用,但本

41、例是指针)。,虚函数的调用是这样进行的,考虑虚函数,Compare(),,则看含“,cat”,的结点。由该结点的,info,指针找到含“,cat”,的无名对象,再由对象前的指针找到,StringObject,虚函数表,移动,4,个字节(一个指针占,4,个字节)找到比较函数指针,进入串比较函数。,完,第八章 继承与派生,谢谢!,【,例,8.1】,由在册人员类公有派生学生类,Person:Person(string,id,string,name,Tsex,sex,int,birthday,string,homeadd,),IdPerson,=id;,Name=,name,;,Sex=,sex,;,

42、Birthday=,birthday,;,HomeAddress,=,homeadd,;,/,作为一个管理程序,这个构造函数并无必要,因为数据总是另外输入的。仅为说明语法存在。,分析构造函数:,【,例,8.1】,由在册人员类公有派生学生类,Person:Person,(),IdPerson,=#;Name=#;Sex=mid;,Birthday=0;HomeAddress=#;,分析默认的构造函数:,分析析构函数:,Person:Person,(),/string,内部动态数组的释放,由,string,自带的析构函数完成,【,例,8.1】,由在册人员类公有派生学生类,void,Person:S

43、etName(string,name),Name=,name,;,/,拷入新姓名,修改名字,:,void,Person:SetHomeAdd(string,homeadd,),HomeAddress,=,homeadd,;,修改住址,:,【,例,8.1】,由在册人员类公有派生学生类,void,Person:PrintPersonInfo,(),int,i;,cout,身份证号,:,IdPerson,n,姓名,:,Namen,性别,:;,if,(Sex,=,man)cout,男,n;,else,if,(Sex,=,woman)cout,女,n;,else,cout,n;,cout,出生年月日,:

44、i=Birthday;,cout,i/10000,年,;,i=i%10000;,cout,i/100,月,i%100,日,n,家庭住址,:,HomeAddress,n;,输出个人信息,:,【,例,8.1】,由在册人员类公有派生学生类,Student:Student(string,id,string,name,Tsex,sex,int,birthday,string,homeadd,string,nostud,),:,Person(id,name,sex,birthday,homeadd,),/,注意,Person,参数表不用类型,int,i,;,NoStudent,=,nostud,;,f

45、or,(i,=0;i30;i+),/,课程与成绩清空,csi.coursename,=#;,csi.grade,=0;,派生类构造函数,:,【,例,8.1】,由在册人员类公有派生学生类,Student:Student,(),/,基类默认的无参数构造函数不必显式给出,int,i,;,NoStudent,=“#;,for,(i,=0;i30;i+),/,课程与成绩清空,将来由键盘输入,csi.coursename,=“#;,csi.grade,=0;,Student:Student,(),/,基类析构函数以及成员对象析构函数自动调用,默认派生类构造函数,:,派生类析构函数,:,【,例,8.1】,由

46、在册人员类公有派生学生类,int,Student:SetCourse(string,coursename,int,grade),bool,b=false;,/,标识新输入的课程,还是更新成绩,int,i,;,for,(i,=0;i30;i+),if,(csi.coursename,=#),/,判表是否进入未使用部分(如有对应删除,应按顺序表方式),csi.coursename,=,coursename,;,csi.grade,=grade;b=,false;,break,;,else,if,(csi.coursename,=,coursename,),/,是否已有该课程记录,csi.grade

47、grade;b,=,true;,break,;,if,(i,=30),return,0;,/,成绩表满返回,0,if,(b,),return,1;,/,修改成绩返回,1,else return,2;,/,登记成绩返回,2,学生类课程设置函数:,【,例,8.1】,由在册人员类公有派生学生类,int,Student:GetCourse(string,coursename,),int,i;,for(i,=0;i30;i+),if,(csi.coursename,=,coursename,),return,csi.grade,;,return,-1;,/,找到返回成绩,未找到返回,-1,查找学生

48、课程成绩函数:,【,例,8.1】,由在册人员类公有派生学生类,void,Student:PrintStudentInfo,(),int,i;,cout,学号,:,NoStudent,n;,PrintPersonInfo,();,for,(i,=0;i30;i+),/,打印各科成绩,if,(csi.coursename,!=#),cout,csi.coursename,t,csi.grade,n;,else,break,;,cout,-,完,-,endl,;,打印学生情况函数:,例,8.1,验证用主函数,:,int,main(void,),char,temp30;,int,i,k,;,Perso

49、n per1(320102820818161,沈俊,man,19820818,南京四牌楼,2,号,);,Person per2;,per2.SetName(,朱明,);,per2.SetSex(woman);,per2.SetBirth(19780528);,per2.SetId(320102780528162);,per2.SetHomeAdd(,南京市成贤街,9,号,);,per1.PrintPersonInfo();,per2.PrintPersonInfo();,Student stu1(320102811226161,朱海鹏,man,19811226,南京市黄浦路,1,号,06000

50、123);,cout,请输入各科成绩,:temp;,/,输入格式,:,物理,80,if,(!strcmp(temp,end,),break,;,cin,k;,i=stu1.SetCourse(temp,k);,if,(i,=0)cout,成绩列表已满,!n;,else,if,(i,=1)cout,修改成绩,n;,else,cout,登记成绩,n;,stu1.PrintStudentInfo();,while,(1),cout,查询成绩,n,请输入科目,:temp;,if,(!strcmp(temp,end,),break,;,k=stu1.GetCourse(temp);,if,(k,=-1)

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服