C--程序设计教程第二版课件.ppt

上传人:小飞机 文档编号:4009295 上传时间:2023-03-31 格式:PPT 页数:61 大小:323.50KB
返回 下载 相关 举报
C--程序设计教程第二版课件.ppt_第1页
第1页 / 共61页
C--程序设计教程第二版课件.ppt_第2页
第2页 / 共61页
C--程序设计教程第二版课件.ppt_第3页
第3页 / 共61页
C--程序设计教程第二版课件.ppt_第4页
第4页 / 共61页
C--程序设计教程第二版课件.ppt_第5页
第5页 / 共61页
点击查看更多>>
资源描述

《C--程序设计教程第二版课件.ppt》由会员分享,可在线阅读,更多相关《C--程序设计教程第二版课件.ppt(61页珍藏版)》请在三一办公上搜索。

1、21:41:12,1,C+程序设计教程(第二版),第十章 继承 Chapter 10 Inheritance,清华大学出版社 钱 能,21:41:12,2,第十章 继 承,继承结构(Inheritance Structure)访问父类成员(Access Fathers Member)派生类的构造(Constructing Derived Classes)继承方式(Inheritance Mode)继承与组合(Inheritance&Composition)多继承概念(Multi-Inheritance Concept)多继承技术(Multi-Inheritance Technology),21

2、:41:12,3,1.继承结构(Inheritance Structure),类层次结构宇宙万事万物都是分类分层的,解决问题可以从事物之间的上下关系中着手这是继承引入程序设计的前提例如:各类型的交通工具之间具有继承关系。,21:41:12,4,21:41:12,5,基类(父类):派生新类的类派生类(子类):从基类派生而成的类基类和派生类:构成类的层次关系单继承:从一个基类派生而成的类多继承:从多个基类派生而成的类继承方式:公有继承、私有继承、保护继承,21:41:12,6,派生类的定义语法:class 派生类名:访问控制 基类名;访问控制:public、protected、private缺省为

3、:private继承方式公有继承 派生时用“public”作访问控制私有继承 派生时用“private”作访问控制保护继承 派生时用“protected”作访问控制,21:41:12,7,继承方式继承方式与访问控制:访问控制符 继承方式 public 公有继承 private 私有继承 protected 保护继承注意:如果类之间没有继承关系则保护成员和私有成员类似;但在类的继承关系中,保护成员在其子类中可以被直接访问,而私有成员在它的子类中也不能被直接访问。,21:41:12,8,公有继承:基类的公有段成员被继承为公有的,基类的保护段成员被继承为保护的。派生时用“public”作访问控制。保

4、护继承:基类的公有段成员和保护段成员被继承为保护的,派生时用“protected”作访问控制。私有继承:基类的公有段成员和保护段成员被继承为私有的,派生时用“private”作访问控制。基类的私有成员在任何情况下都是基类所私有的,在基类以外都不能访问!,21:41:12,9,公有成员:一个类的公有成员允许本类的成员函数、本类的对象、派生类的成员函数、公有派生类的对象直接访问,不允许保护和私有派生类的对象直接访问。私有成员:一个类的私有成员只允许本类的成员函数直接访问。保护成员:允许本类的成员函数、派生类的成员函数直接访问,不允许对象直接访问。,21:41:12,10,21:41:12,11,例

5、如:一个含有不同继承方式的类的继承结构。class Base int b1;protected:int b2;void fb2()b1=1;public:int b3;void fb3()b1=1;,21:41:12,12,class Pri:private Basepublic:void test()b1=1;/error b2=1;/ok b3=1;/ok fb2();/ok fb3();/ok;,class FromPri:public Pripublic:void test()b1=1;/error b2=1;/error b3=1;/error fb2();/error fb3();

6、/error;,21:41:12,13,class Pro:protected Basepublic:void test()b1=1;/error b2=1;/ok b3=1;/ok fb2();/ok fb3();/ok;,class FromPro:public Propublic:void test()b1=1;/error b2=1;/ok b3=1;/ok fb2();/ok fb3();/ok;,21:41:12,14,class Pub:public Basepublic:void test()b1=1;/error b2=1;/ok b3=1;/ok fb2();/ok fb3

7、();/ok;,class FromPub:public Pubpublic:void test()b1=1;/error b2=1;/ok b3=1;/ok fb2();/ok fb3();/ok;,21:41:12,15,int main()Pri priObj;priObj.b1=1;/error priObj.b2=1;/error priObj.b3=1;/error Pro proObj;proObj.b1=1;/error proObj.b2=1;/error proObj.b3=1;/error Pub pubObj;pubObj.b1=1;/error pubObj.b2=1

8、;/error pubObj.b3=1;/ok,21:41:12,16,说明:私有继承时,基类中不管是公有的,还是保护的,一律在子类中变成私有成员。保护继承时,基类中公共和保护的成员在子类中变成保护的。公共继承时,基类中为公共、保护的成员在子类中仍保持为公共、保护的。在继承关系中,基类的private成员不但对应用程序隐藏,对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。,21:41:12,17,在派生类中,可以调整成员的访问控制属性!class Base int b1;protected:int b2;void fb2()b1=1;public:int b3;voi

9、d fb3()b1=1;class Pri:private Basepublic:using Base:fb3;/fb3从私有转为公有 using Base:b1;/error!b1不可见;int main()Pri pri;pri.fb3();/ok,21:41:12,18,说明:在派生类中调整访问控制属性的前提是在派生类中该成员必须是可见的注意:在写程序时,数据成员一般设置为私有的;,21:41:12,19,派生类对象结构,对于下面的继承关系:class Father int a,b;public:/成员函数;class Son:public Father int c;public:/成员

10、函数;,基类对象子类对象说明:派生类中含有基类的数据成员,子类对象空间总是不小于基类对象,c,a,b,a,b,基类部分,子类添加部分,21:41:12,20,2.访问父类成员(Access Fathers Member),继承父类成员例如:有一个学生类Student,现在要增加研究生类,研究生类除了自己所特有的性质外,还具有学生类的所有性质,下面用继承的方法来重用学生类的代码。,21:41:12,21,class Advisor/导师类 int noOfMeeting;class Student/学生类 string name;int semesterHours;/学时 double aver

11、age;/平均分public:Student(string pName=noName):name(pName),average(0),semesterHours(0),21:41:12,22,void addCourse(int hours,double grade)double totalGrade=(semesterHours*average+grade);/总分 semesterHours+=hours;/总修学时 average=semesterHours?totalGrade/semesterHours:0;/平均分 void display()coutname=name,hours

12、=“semesterHours,average=averagen;int getHours()return semesterHours;double getAverage()return average;,21:41:12,23,class GraduateStudent:public Student/研究生类(继承学生类)Advisor advisor;/导师 int qualifierGrade;/资格考试分数public:int getQualifier()return qualifierGrade;int main()Student ds(Lo lee undergrade);Grad

13、uateStudent gs;ds.addCourse(3,2.5);ds.display();gs.addCourse(3,3.0);gs.display();运行结果:name=Lo lee Undergrad,hours=3,average=0.833333 name=no name,hours=3,average=1,21:41:12,24,void fn(Student函数fn()期望接受Student类对象作为它的参数,来自main()的调用传给它一个GraduateStudent类对象,fn()把它视作Student类对象予以接受。事实上,GraduateStudent的内存布局

14、,也与“gs是研究生,当然也是学生”相吻合。,21:41:12,25,说明:捆绑子类对象可以访问父类成员函数和自身成员函数;捆绑基类对象只能访问基类成员函数,不能访问子类成员函数:ds.addCourse(3,2.5);ds.display();ds.getQualifier();/error gs.addCourse(3,3.0);gs.display();gs.getQualifier();,21:41:12,26,class Father int a;protected:void fp()couta;public:void print()couta;,外来用户:void fn()Son

15、d;d.print();/ok d.disp();/ok d.fp();/error Father f;f.print();/ok f.fp();/error f.disp();/error,子类用户:class Son:public Father int b;public:void disp()fp();/ok print();/ok void ed()a+;/error;,21:41:12,27,3.构造子类对象(Constructing Objects of SubClass),继承中的构造函数和析构函数的说明:1.派生类构造函数的初始化列表中列出的均是直接基类的构造函数。2.构造函数不

16、能被继承,因此派生类的构造函数只能通过调用基类的某个构造函数(如果有定义的话)来初始化基类子对象。3.派生类的构造函数只负责初始化自己定义的数据成员。,21:41:12,28,4.派生类构造函数被调用时,在还没有执行构造函数体之前,先调用基类的构造函数,再调用派生类对象成员所属类的构造函数,完成对象所需空间的分配;最后执行派生类自身的构造函数。(若基类上面还有基类,优先调用上面基类的构造函数;派生类的对象成员的构造函数被调用的顺序取决于在类中声明的顺序)5.派生类的对象的生存期结束时调用派生类的析构函数,在该析构函数结束之前再调用基类的析构函数;所以,析构函数的被调用次序与构造函数相反。,21

17、:41:12,29,默认构造:如果子类没有构造函数,则调用默认无参构造函数,默认构造函数首先调用父类的无参构造函数,完成父类对象部分的构造,然后构造自身如果父类的上面还有父类,则依次递归,21:41:12,30,自定义构造:为了规定父类构造函数的调用方式,而不是默认调用,需要自定义子类构造函数,并且,在子类构造函数定义体的始化列表中(即冒号后面)描述父类构造函数的调用形式 描述形式与对象成员构造的描述一致,21:41:12,31,class Advisor int noOfMeeting;public:Advisor()coutAdvisorn;Advisor(const Advisorpub

18、lic:Student(string pName=noName):name(pName),average(0),semesterHours(0),21:41:12,32,void addCourse(int hours,double grade)double totalGrade=(semesterHours*average+grade);/总分 semesterHours+=hours;/总修学时 average=semesterHours?totalGrade/semesterHours:0;/平均分 void display()coutname=name,hours=“semesterH

19、ours,average=averagen;int getHours()return semesterHours;double getAverage()return average;Student()coutStudentn;,21:41:12,33,class GraduateStudent:public Student Advisor advisor;int qualifierGrade;public:GraduateStudent(const string,21:41:12,34,void fn(Advisor,运行结果:Advisorcopy Advisorname=Yen Kay D

20、oodle,hours=0,average=0GraduateStudentAdvisorStudentAdvisor,21:41:12,35,说明:1)派生类对象构造时,先构造基类,再对象成员,最后是派生类自身2)派生类构造函数的初始化列表中,直接调用基类的构造函数3)如果派生类中定义了与基类名字相同的成员,捆绑子类对象访问此成员时,则首先匹配子类,然后父类,再父类的父类,依此类推gs.display();/call GraStudent:display(),21:41:12,36,拷贝构造:子类若没有定义拷贝构造函数,则子类对象在拷贝创建时先调用父类的拷贝构造函数,再调用自己的默认拷贝构造

21、函数完成自己的位对位拷贝若父类没有定义拷贝构造函数,则子类对象在拷贝创建中调用父类默认的拷贝构造函数同样,如果子类申请了资源,需要定义拷贝构造函数赋值操作符“”原理相似当使用子类为父类初始化或赋值时:Student ds=gs;(使用gs对象中基类部分)ds=gs;,21:41:12,37,5.继承与组合(Inheritance&Composition),组合:新的、复杂的对象由已存在的、相对简单的对象组成。即:类的数据成员是另一个类的对象。对象由若干个子对象组成。类中含有对象成员,称为组合式包含继承:子类继承了父类,称为子类对象对父类对象的继承式包含继承和组合都重用了类设计,21:41:12

22、,38,GraduateStudent组合了Advisor称GraduateStudent 有一个AdvisorGraduateStudent类继承了Student类称GraduateStudent 是一个Student,21:41:12,39,继承与组合两者在使用上不同继承重用场合,子类就是一种父类,所以,无须捆绑父类对象便能直接对其共有和保护成员操作组合重用场合,使用对象成员的操作,只能捆绑对象成员对其公有成员进行操作。void GraduateStudent:print()display();/继承得到 coutGraduateStudentn;advisor.print();/组合方式

23、,21:41:12,40,例:class Vehicle/车辆类/;class Motor/发动机类/;class Car:public Vehicle public:Motor motor;void vehicleFn(Vehicle,/ok,/ok,/error,21:41:12,41,继承型的Circle类头文件:#includepoint.hclass Circle:public Point double radius;public:/成员函数;,组合型的Circle类头文件:#includepoint.hclass Circle Point point;double radius;p

24、ublic:/成员函数;,公有成员函数实现不同,但可以让界面相同,从而不影响编程者使用,继承与组合在于实现技术不同,21:41:12,42,使用含有继承和组合的子类:只要外界不直接或无法直接使用该子类的祖先类成员或对象成员,仅提供公有的成员函数,则对外界来说,无所谓该子类的继承式包含还是组合式包含(包含组合或继承的哪种头文件都可):#include”point.h”#include“circle.h”/组合或继承int fn()Circle c(Point(2.3,5.6),7);c.moveTo(1,2);c.modifyRadius(3);/,21:41:12,43,6.多继承概念(Mul

25、ti-Inheritance Concept),多重继承即多继承:由多个基类派生新的类 例如,两用沙发,它是一个沙发,也是一张床,两用沙发应允许同时继承沙发和床的特性,即SleeperSofa类继承Bed和Sofa两个类。,21:41:12,44,21:41:12,45,class Bedprotected:int weight;public:Bed():weight(0)void sleep()const coutSleeping.n;void setWeight(int i)weight=i;,class Sofaprotected:int weight;public:Sofa():wei

26、ght(0)void watchTV()const cout Watching TV.n;void setWeight(int i)weight=i;,21:41:12,46,class SleeperSofa:public Bed,public Sofapublic:SleeperSofa()void foldOut()const cout Fold out the sofa.n;/-int main()SleeperSofa ss;ss.watchTV();ss.foldOut();ss.sleep();,运行结果:Watching TV.Fold out the sofa.Sleepin

27、g,21:41:12,47,基类成员名冲突int main()sleepersofa ss;ss.SetWeight(20);/error/是Bed的SetWeight还是sofa的SetWeight?这导致了名称冲突,在编译时将予以拒绝。程序必须在重量面前说明基类void main()sleepersofa ss;ss.Sofa:SetWeight(20);/说明是沙发重量20斤,21:41:12,48,基类分解从意义上来看,一个SleepSofa没有沙发和床两种重量,如此的继承不是真实的现实世界描述。进一步分析可得,床和沙发都是家具的一种,凡家具都有重量,所以通过分解来考察其关系。,21:

28、41:12,49,21:41:12,50,class Furniture public:Furniture():weight(0)void SetWeight(int i)weight=i;int GetWeight()const return weight;protected:int weight;class Bed:public Furniture public:Bed()void Sleep()const cout Sleeping.n;,21:41:12,51,class Sofa:public Furniture public:Sofa()void WatchTV()const co

29、ut GetWeight()endl;,21:41:12,52,完整的SleeperSofa对象内存布局,由于SleepSofa不是直接继承Furniture,而是Bad和Sofa各自继承Furniture,所以完整的SleepSofa对象内存布局如下图所示。,21:41:12,53,7.多继承技术(Multi-Inheritance Technology),虚拟继承虚拟继承的概念:在多条继承路径上存在一个公共的基类,在这些路径的汇合处(某个派生类)就产生这个公共基类的多个“副本”。如果只希望存在一个副本,可以在派生子类时把此公共基类声明为虚基类(虚拟继承)。虚拟继承的方法:虚基类是对派生类而

30、言,所以,虚基类本身的定义不变,在定义派生类时声明该基类为虚基类即可(冠以关键字:virtual)。,21:41:12,54,虚拟继承的作用:多个不同子类(如,床、沙发)在继承基类的方式上采取虚拟继承,它的作用是,当对象创建上产生基类重叠时,略去重复产生基类对象空间的行为:,21:41:12,55,class Furniture public:Furniture():weight(0)void SetWeight(int i)weight=i;int GetWeight()const return weight;protected:int weight;class Bed:virtual pu

31、blic Furniture public:Bed()void Sleep()const cout Sleeping.n;,21:41:12,56,class Sofa:virtual public Furniture public:Sofa()void WatchTV()const cout Watching TV.n;class SleeperSofa:public Bed,public Sofa public:SleeperSofa():Sofa(),Bed()void FoldOut()const cout Fold out the sofa.n;int main()SleeperSo

32、fa ss;ss.SetWeight(20);cout ss.GetWeight()endl;运行结果:20,21:41:12,57,21:41:12,58,多继承对象的构造顺序派生类的构造函数调用次序(调用原则):先基类,再成员,后自己1.在同一层上如有多个基类,则先虚基类,后非虚基类 在同一层上如有多个虚基类,则按其被继承的先后次序构造 在同一层上如有多个非虚基类,则按其被继承的先后次序构造2.成员对象的构造函数按它们声明的次序调用3.类自己的构造函数,21:41:12,59,#includeusing namespace std;class OBJ1 public:OBJ1()cout

33、OBJ1n;class OBJ2 public:OBJ2()cout OBJ2n;class Base1 public:Base1()cout Base1n;class Base2 public:Base2()cout Base2n;,21:41:12,60,class Base3 public:Base3()cout Base3n;class Base4 public:Base4()cout Base4n;class Derived:public Base1,virtual public Base2,public Base3,virtual public Base4 protected:OBJ1 obj1;OBJ2 obj2;public:Derived():Base4(),Base3(),Base2(),Base1(),obj2(),obj1()cout Derived ok.n;,21:41:12,61,void main()Derived aa;cout This is ok.n;运行结果:Base2 Base4 Base1 Base3 OBJ1 OBJ2 Derived ok.This is ok.,在语言中实现多重继承并不容易,这主要是编译程序问题,还有模糊性问题。建议你如果可能,尽量避免用多重继承。单个继承提供了足够的功能,不一定非用多重继承不可。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号