版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、主讲人:主讲人:XXX电子邮件:电子邮件:联系电话:联系电话:第八章第八章 继承与多态继承与多态Page 2计算机基础教研室计算机基础教研室本章主要内容本章主要内容8.1 继承与派生的概念继承与派生的概念 8.4 虚基类虚基类 (选读)(选读) 8.3 多重继承与派生类成员标识多重继承与派生类成员标识 (选读选读) 8. 6 多态性与虚函数多态性与虚函数 8.5 派生类应用讨论派生类应用讨论 8.2 派生类的构造函数与析构函数派生类的构造函数与析构函数 Page 3计算机基础教研室计算机基础教研室继承继承(inheritance)(inheritance):该机制是面向对象程序设计使代码可以复
2、用的最重要的手该机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。增加功能。这样产生新的类,称派生类。继承呈现了面向这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。对象程序设计的层次结构。体现了由简单到复杂的认识过体现了由简单到复杂的认识过程程。多态性多态性(polymorphism):(polymorphism):多态性包括静态的多态性和动态的多态性。前者亦称编译多态性包括静态的多态性和动态的多态性。前者亦称编译时的多态性,包括函数的重载和运算符的重载。后者亦称时的多态
3、性,包括函数的重载和运算符的重载。后者亦称运行时的多态性,这是以虚函数为基础的,是面向对象程运行时的多态性,这是以虚函数为基础的,是面向对象程序设计的标志性特征。序设计的标志性特征。 体现了类推和比喻的思想方法。体现了类推和比喻的思想方法。 继承与多态继承与多态Page 4计算机基础教研室计算机基础教研室层次概念层次概念是计算机的重要概念。通过是计算机的重要概念。通过继承继承(inheritance)的机制可对类(的机制可对类(class)分层,提供类型)分层,提供类型/子类型的关系。子类型的关系。 C+通过通过类派生类派生(class derivation)的机制来支持继承。)的机制来支持继
4、承。被继承的类称为被继承的类称为基类基类(base class)或)或超类超类(superclass),),新的类为新的类为派生类派生类(derived class)或)或子类子类(subclass)。)。基基类和派生类的集合称作类和派生类的集合称作类继承层次结构类继承层次结构(hierarchy)。)。 如果基类和派生类共享相同的公有接口,则派生类被称作如果基类和派生类共享相同的公有接口,则派生类被称作基类的子类型(基类的子类型(subtype)。)。 层次概念:层次概念:派生反映了事物之间的联系,事物的共性与个性之间的关系。派生反映了事物之间的联系,事物的共性与个性之间的关系。 派生与独立
5、设计若干相关的类,前者工作量少,重复的部分派生与独立设计若干相关的类,前者工作量少,重复的部分可以从基类继承来,不需要单独可以从基类继承来,不需要单独编程编程。 继承与派生的概念继承与派生的概念Page 5计算机基础教研室计算机基础教研室8.1.1 8.1.1 类的派生与继承类的派生与继承 8.1.2 8.1.2 公有派生与私有派生公有派生与私有派生 继承与派生的概念继承与派生的概念Page 6计算机基础教研室计算机基础教研室派生类的定义:派生类的定义:class 派生类名:访问限定符派生类名:访问限定符 基类名基类名1,访问限定符,访问限定符 基类名基类名2,访问限定符,访问限定符 基类名基
6、类名n private: 成员表成员表1; /派生类增加或替代的私有成员派生类增加或替代的私有成员 public:成员表成员表2; /派生类增加或替代的公有成员派生类增加或替代的公有成员 protected:成员表成员表3; /派生类增加或替代的保护成员派生类增加或替代的保护成员;/分号不可少分号不可少其中基类其中基类1 1,基类,基类2 2,是已声明的类。是已声明的类。 在派生类定义的类体中在派生类定义的类体中给出的成员称为给出的成员称为派生类成员派生类成员,它们是新增加成员,它们给派生类,它们是新增加成员,它们给派生类添加了不同于基类的新的属性和功能。派生类成员也包括取代基添加了不同于基类
7、的新的属性和功能。派生类成员也包括取代基类成员的更新成员。类成员的更新成员。类的派生与继承类的派生与继承Page 7计算机基础教研室计算机基础教研室访问限定符两方面含义:访问限定符两方面含义:派生类成员(新增成派生类成员(新增成员)函数对基类(继承来的)成员的访问(调用和员)函数对基类(继承来的)成员的访问(调用和操作)操作),和,和从派生类对象之外对派生类对象中的基从派生类对象之外对派生类对象中的基类成员的访问类成员的访问。放在后面讨论。放在后面讨论。 公有派生限制最少,是派生的主流。公有派生限制最少,是派生的主流。访问限定符:访问限定符:基类名前的访问限定符,是对基类成员进一步的限制。基类
8、名前的访问限定符,是对基类成员进一步的限制。访问控制也是三种:访问控制也是三种:公有(公有(publicpublic)方式,亦称公有继承)方式,亦称公有继承保护(保护(protectedprotected)方式,亦称保护继承)方式,亦称保护继承私有(私有(privateprivate)方式,)方式, 亦称私有继承。亦称私有继承。 类的派生与继承类的派生与继承Page 8计算机基础教研室计算机基础教研室多重继承:多重继承:如果一个派生类可以同时有多个基类,称如果一个派生类可以同时有多个基类,称为多重继承(为多重继承(multiple-inheritance),这时的派生类同),这时的派生类同时得
9、到了多个已有类的特征。时得到了多个已有类的特征。单继承:单继承:派生类只有一个直接基类的情况称为单继承派生类只有一个直接基类的情况称为单继承(single-inheritance)。)。类的派生与继承类的派生与继承Page 9计算机基础教研室计算机基础教研室基类基类1基类基类2基类基类n派生类派生类1派生类派生类2基类基类派生类派生类1派生类派生类2(a)多重继承)多重继承 (b)单继承)单继承 一个基一个基类可以类可以直接派直接派生出多生出多个派生个派生类类 派生类可派生类可以由多个以由多个基类共同基类共同派生出来,派生出来,称多重继称多重继承。承。类的派生与继承类的派生与继承Page 10
10、计算机基础教研室计算机基础教研室 在派生过程中,派生出来的新类同样可以在派生过程中,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形作为基类再继续派生出更新的类,依此类推形成一个层次结构。直接参与派生出某类称为直成一个层次结构。直接参与派生出某类称为直接基类,而基类的基类,以及更深层的基类称接基类,而基类的基类,以及更深层的基类称为为间接基类间接基类。类族:类族: 同时一个基类可以直接派生出多个派生类。同时一个基类可以直接派生出多个派生类。这样形成了一个相互关联的类族。如这样形成了一个相互关联的类族。如MFC就是就是这样的族类,它由一个这样的族类,它由一个CObject类派生出类
11、派生出200个个MFC类中的绝大多数。类中的绝大多数。 多层次继承:多层次继承:类的派生与继承类的派生与继承Page 11计算机基础教研室计算机基础教研室编制编制派生派生类时类时可分可分四步四步 吸收基类的成员吸收基类的成员 改造基类成员改造基类成员 发展新成员发展新成员 重写构造函数与析构函数重写构造函数与析构函数 不论是数据成员,还是函数成员,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收除构造函数与析构函数外全盘接收 声明一个和某基类成员同名的新成员声明一个和某基类成员同名的新成员, ,派派生类中的新成员就屏蔽了基类同名成员生类中的新成员就屏蔽了基类同名成员派生类新成员必须
12、与基类成员不同名,它派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。的加入保证派生类在功能上有所发展。 派生编程步骤:派生编程步骤:类的派生与继承类的派生与继承Page 12计算机基础教研室计算机基础教研室第二步中,第二步中,新成员新成员如是成员函数,参数表和返回值也完如是成员函数,参数表和返回值也完全一样,称为同名覆盖全一样,称为同名覆盖(Override),否则是重载,否则是重载 。第三步中,独有的新成员才是继承与派生的核心特征。第三步中,独有的新成员才是继承与派生的核心特征。第四步是重写构造函数与析构函数,派生类不继承这两第四步是重写构造函数与析构函数,派生类不继承
13、这两种函数。不管原来的函数是否可用种函数。不管原来的函数是否可用一律重写可免出错一律重写可免出错。方式类似聚合方式类似聚合含成员对象的类的构造函数含成员对象的类的构造函数。详细内。详细内容后文讨论。容后文讨论。类的派生与继承类的派生与继承Page 13计算机基础教研室计算机基础教研室【例例8.1】由在册人员类公有派生学生类。我们希望基类和派生类由在册人员类公有派生学生类。我们希望基类和派生类共享相同的公有接口共享相同的公有接口,只能采用公有派生来实现。只能采用公有派生来实现。基类:基类:class Personstring IdPerson;/身份证号身份证号,18位数字位数字string N
14、ame;/姓名姓名Tsex Sex; /性别性别enum Tsexmid,man,woman;int Birthday;/生日生日,格式格式1986年年8月月18日写作日写作19860818string HomeAddress;/家庭地址家庭地址public:Person(string, string,Tsex,int, string);/构造函数构造函数 Person(); /默认的构造函数默认的构造函数 Person(); /析构函数析构函数【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类Page 14计算机基础教研室计算机基础教研室void SetName(str
15、ing); /修改名字修改名字string GetName()return Name; /提取名字提取名字void SetSex(Tsex sex)Sex=sex; /修改性别修改性别Tsex GetSex()return Sex; /提取性别提取性别void SetId(string id)IdPerson=id;/修改身份证号修改身份证号string GetId()return IdPerson; /提取身份证号提取身份证号void SetBirth(int birthday)Birthday=birthday; /修改生日修改生日int GetBirth()return Birthday
16、; /提取生日提取生日void SetHomeAdd(string ); /修改住址修改住址string GetHomeAdd()return HomeAddress; /提取住址提取住址void PrintPersonInfo(); /输出个人信息输出个人信息;/接口函数:接口函数:【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类Page 15计算机基础教研室计算机基础教研室派生的学生类派生的学生类: :class Student:public Person /定义派生的学生类定义派生的学生类 string NoStudent; /学号学号 course cs30;
17、/30门课程与成绩门课程与成绩public: Student(string id, string name,Tsex sex,int birthday, string homeadd, string nostud);/注意注意派生类构造函数派生类构造函数声明方式声明方式 Student(); /默认派生类构造函数默认派生类构造函数 Student(); /派生类析构函数派生类析构函数 SetCourse(string ,int); /课程设置课程设置 int GetCourse(string ); /查找成绩查找成绩 void PrintStudentInfo(); /打印学生情况打印学生情况
18、;struct course string coursename; int grade;【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类Page 16计算机基础教研室计算机基础教研室int main(void) char temp30; int i,k; Person per1(320102820818161,沈俊沈俊, man,19820818,南京四牌楼南京四牌楼2号号); Person per2; per2.SetName(朱明朱明); per2.SetSex(woman); per2.SetBirth(19780528); per2.SetId(32010278
19、0528162); per2.SetHomeAdd(南京市成贤街南京市成贤街9号号); per1.PrintPersonInfo(); per2.PrintPersonInfo(); Student stu1(320102811226161,朱海鹏朱海鹏, man,19811226,南京市黄浦路南京市黄浦路1号号,06000123); cout请输入各科成绩请输入各科成绩:temp; /输入格式输入格式:物理物理 80 if(!strcmp(temp,end) break; cink; i=stu1.SetCourse(temp,k); if(i=0) cout成绩列表已满成绩列表已满!n;
20、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) cout未查到未查到n; else coutkn; return 0;Page 18计算机基础教研室计算机基础教研室注意:注意: 本例中标准本例中标准C+字符串字符串string是作为成员对象使用的是作为成员对象使用的(聚合聚合),动态内存分配的构造和析
21、构被封装起来,使用十),动态内存分配的构造和析构被封装起来,使用十分简单。如使用动态生成的分简单。如使用动态生成的C风格字符串,要考虑深复制,风格字符串,要考虑深复制,那要复杂得多。那要复杂得多。 提倡完善的类对象封装,不仅封装数据和对数据的操作,提倡完善的类对象封装,不仅封装数据和对数据的操作,而且封装资源的动态分配与释放,形成一个完备的子系统。而且封装资源的动态分配与释放,形成一个完备的子系统。在一个有层次结构的类体系中资源的动态分配与释放应封装在一个有层次结构的类体系中资源的动态分配与释放应封装在成员对象中在成员对象中,如同使用标准的,如同使用标准的string字符串类那样。字符串类那样
22、。 聚合是一种完善的封装。采用成员对象将大大简化层次聚合是一种完善的封装。采用成员对象将大大简化层次结构的类体系中资源的动态分配与释放的处理方法,不再出结构的类体系中资源的动态分配与释放的处理方法,不再出现难度极大的多层次的深复制。现难度极大的多层次的深复制。派生类的构造函数与析构函数派生类的构造函数与析构函数Page 19计算机基础教研室计算机基础教研室访问限定符讨论:访问限定符讨论:派生类成员(新增成员)函数对基类(继承来派生类成员(新增成员)函数对基类(继承来的)成员的访问(调用和操作)的)成员的访问(调用和操作),和,和从派生从派生类对象之外对派生类对象中的基类成员的访类对象之外对派生
23、类对象中的基类成员的访问问。下面进行详细讨论:下面进行详细讨论:公有派生与私有派生公有派生与私有派生Page 20计算机基础教研室计算机基础教研室不可直接访问 不可直接访问 private 不可直接访问 private protected 不可直接访问 private public 私有派生所有接口必须重写 不可直接访问 不可直接访问 private 不可直接访问 protected protected 可直接访问 public public 公有派生所有接口均可使用 在派生类对象外访问派生类对象的基类成员 在派生类中对基类成员的访问限定 基类中的访问限定 派生方式 公有派生是绝对主流公有派生
24、是绝对主流 公有派生与私有派生公有派生与私有派生Page 21计算机基础教研室计算机基础教研室直接派生直接派生: : 基类的私有成员仍是派生类的私有成基类的私有成员仍是派生类的私有成员,不可直接访问,而基类中的公有和保护成员员,不可直接访问,而基类中的公有和保护成员全部成为派生类的保护成员,在派生类中可以直全部成为派生类的保护成员,在派生类中可以直接访问。但在派生类对象之外是不能直接访问该接访问。但在派生类对象之外是不能直接访问该对象的任何基类成员的。与私有派生相同。对象的任何基类成员的。与私有派生相同。公有派生与私有派生公有派生与私有派生保护派生保护派生: :Page 22计算机基础教研室计
25、算机基础教研室多层派生:多层派生:把保护派生类作为基类或把私有派生类作为把保护派生类作为基类或把私有派生类作为基类再作一层保护派生。基类再作一层保护派生。在新的保护派生类中可直接访问由保护派生传递过来的底在新的保护派生类中可直接访问由保护派生传递过来的底层基类的公有和保护成员,而不可直接访问由私有派生传层基类的公有和保护成员,而不可直接访问由私有派生传递来的底层基类的公有和保护成员。递来的底层基类的公有和保护成员。但在该类对象之外都不可直接访问类对象底层基类的公有但在该类对象之外都不可直接访问类对象底层基类的公有成员。合理使用保护限定方式可以在复杂的类层次关系中成员。合理使用保护限定方式可以在
26、复杂的类层次关系中取一个共享访问和成员封装隐蔽性的折衷。取一个共享访问和成员封装隐蔽性的折衷。公有派生与私有派生公有派生与私有派生保护派生保护派生: :Page 23计算机基础教研室计算机基础教研室派生类名派生类名:派生类名(参数总表)派生类名(参数总表):基类名基类名1(参数名表(参数名表1),),基类名基类名2(参数名表(参数名表2),),基类名,基类名n(参数名表(参数名表n),),成员对象名成员对象名1(成员对象参数名表(成员对象参数名表1),),成员对象名,成员对象名m(成员对象参数名表(成员对象参数名表m)/派生类新增成员的初始化;派生类新增成员的初始化; /所列出的成员对象名全部
27、为新增成员对象的名字所列出的成员对象名全部为新增成员对象的名字派生类的构造函数与析构函数派生类的构造函数与析构函数派生类构造函数的定义:派生类构造函数的定义:Page 24计算机基础教研室计算机基础教研室注意:注意: 在构造函数的声明中,冒号及冒号以后部分必须略去。在构造函数的声明中,冒号及冒号以后部分必须略去。 所谓不能继承并不是不能利用,而是把基类的构造函数作所谓不能继承并不是不能利用,而是把基类的构造函数作为新的构造函数的一部分,或者讲调用基类的构造函数。为新的构造函数的一部分,或者讲调用基类的构造函数。基基类名仅指直接基类,写了底层基类,编译器认为出错类名仅指直接基类,写了底层基类,编
28、译器认为出错。 冒号后的基类名,成员对象名的次序可以随意,这里的次冒号后的基类名,成员对象名的次序可以随意,这里的次序与调用次序无关。序与调用次序无关。 派生类的构造函数与析构函数派生类的构造函数与析构函数派生类构造函数的定义:派生类构造函数的定义:Page 25计算机基础教研室计算机基础教研室派生类构造函数各部分执行次序:派生类构造函数各部分执行次序: 1.1.调用基类构造函数,按它们在派生类定义的先调用基类构造函数,按它们在派生类定义的先后顺序,顺序调用。后顺序,顺序调用。 2.2.调用成员对象的构造函数,按它们在类定义中调用成员对象的构造函数,按它们在类定义中声明的先后顺序,顺序调用。声
29、明的先后顺序,顺序调用。3.3.派生类的构造函数体中的操作。派生类的构造函数体中的操作。派生类的构造函数与析构函数派生类的构造函数与析构函数Page 26计算机基础教研室计算机基础教研室注意:注意: 在派生类构造函数中,只要基类不是使用无参的默认在派生类构造函数中,只要基类不是使用无参的默认构造函数都要显式给出基类名和参数表构造函数都要显式给出基类名和参数表。 如果基类没有定义构造函数,则派生类也可以不定义,如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。全部采用系统给定的默认构造函数。 如果基类定义了带有形参表的构造函数时,派生类就如果基类定义了带有形参表的构
30、造函数时,派生类就应当定义构造函数。应当定义构造函数。派生类的构造函数与析构函数派生类的构造函数与析构函数Page 27计算机基础教研室计算机基础教研室析构函数:析构函数:析构函数析构函数的功能是作善后工作。的功能是作善后工作。 只要在函数体内把派生类新增的一般成员处理只要在函数体内把派生类新增的一般成员处理好就可以了好就可以了,而,而对新增的成员对象和基类的善后工对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来作,系统会自己调用成员对象和基类的析构函数来完成完成。 析构函数各部分执行次序与构造函数相反,析构函数各部分执行次序与构造函数相反,首首先对派生类新增一般成员
31、析构,然后对新增对象成先对派生类新增一般成员析构,然后对新增对象成员析构,最后对基类成员析构员析构,最后对基类成员析构。派生类的构造函数与析构函数派生类的构造函数与析构函数Page 28计算机基础教研室计算机基础教研室由多个基类共同派生出新的派生类,这样的继承结构由多个基类共同派生出新的派生类,这样的继承结构被称为多重继承或多继承(被称为多重继承或多继承(multiple-inheritance) 椅子椅子床床沙发沙发(单继承单继承)躺椅躺椅(多重继承多重继承)两用沙发两用沙发(多重继承多重继承)图图8.2 椅子,床到两用沙发椅子,床到两用沙发多重继承实例:多重继承实例:多重继承与派生类成员标
32、识(选读)多重继承与派生类成员标识(选读)Page 29计算机基础教研室计算机基础教研室在册人员在册人员学生学生(单继承单继承)教职工教职工(单继承单继承)兼职教师兼职教师(单继承单继承)教师教师(单继承单继承)行政人员行政人员(单继承单继承)工人工人(单继承单继承)研究生研究生(单继承单继承)行政人员兼教师行政人员兼教师(多重继承多重继承)在职研究生在职研究生(多重继承多重继承)研究生助教研究生助教(多重继承多重继承)图图8.3 大学在册人员继承关系大学在册人员继承关系派生出来派生出来的新类同的新类同样可以作样可以作为基类再为基类再继续派生继续派生出更新的出更新的类,依此类,依此类推形成类推
33、形成一个一个层次层次结构结构。 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)Page 30计算机基础教研室计算机基础教研室歧义性问题歧义性问题: :参见图参见图8.3,比如行政人员兼教师,在其基类教师中有一个,比如行政人员兼教师,在其基类教师中有一个“教职工编号教职工编号”,另一基类行政人员中也有一个,另一基类行政人员中也有一个“教职工编教职工编号号”,如果只讲教职工编号那么是哪一个基类中的呢?这两,如果只讲教职工编号那么是哪一个基类中的呢?这两者可能是一回事,但者可能是一回事,但计算机系统并不这么认为计算机系统并不这么认为。进一步,如果进一步,如果“教职工编号教职工编号”
34、 是由两个基类是由两个基类“教师教师”和和“行行政人员政人员”共同的基类共同的基类“教职工教职工”类继承来的,只有同一个标类继承来的,只有同一个标识符,也不能用改标识符来区分。识符,也不能用改标识符来区分。 唯一标识问题:唯一标识问题:通常采用作用域分辨符通常采用作用域分辨符“:”:基类名基类名:成员名成员名; /数据成员数据成员基类名基类名:成员名成员名(参数表参数表); /函数成员函数成员 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)Page 31计算机基础教研室计算机基础教研室class EGStudent int No在职学号 class GStudent int
35、No研究生号研究生号 .class Student int No学生号学生号 . class Person int No身份证号身份证号 .class Employee int No工作证号工作证号 .class Person int No身份证号身份证号 .图图8.4(a)在职研究生派生类关系)在职研究生派生类关系 定义定义EGStudent类对象类对象EGStudent1,并假定派生全部为公有派生,并假定派生全部为公有派生,而而int No全为公有成员全为公有成员:EGStud1.No /在职学号在职学号EGStud1.GStudent:No /研究生号研究生号EGStud1.GStude
36、nt.Student:No /学生号学生号 EGStud1.GStudent.Student. Person:No /身份证号身份证号EGStud1.Employee:No /工作证号工作证号EGStud1.Employee.Person:No /身份证号身份证号两个身份证号从逻辑上两个身份证号从逻辑上讲应是一回事讲应是一回事,但是物理但是物理上是分配了不同内存空上是分配了不同内存空间,是两个变量,请参间,是两个变量,请参见图见图8.4(b)。Page 32计算机基础教研室计算机基础教研室Person Person StudentEmployee GStudent EGStudentPerso
37、n成员成员 Person成员成员 Student新成员新成员 GStudent新成员新成员 Employee新成员新成员 EGStudent新成员新成员 图图8.4(b)在职研究)在职研究生派生类存储图生派生类存储图 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)Page 33计算机基础教研室计算机基础教研室 建议采用有确定字面意思的标识符,它可以被编译器简单区分出建议采用有确定字面意思的标识符,它可以被编译器简单区分出来。来。 如果如果class Person的身份证号标识为的身份证号标识为int IdPerson,则写为:,则写为:EGStud1.GStudent:IdP
38、ersonEGStud1.Employee:IdPerson不必标出那么多层次的类,但写不必标出那么多层次的类,但写EGStud1:IdPerson是错的。是错的。 作用域分辨符不能嵌套使用作用域分辨符不能嵌套使用,如:,如:EGStud1.GStudent:Student:No /学生号学生号EGStud1.GStudent:Student:Person:No /身份证号身份证号是是错误错误的。的。 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)Page 34计算机基础教研室计算机基础教研室一般数据成员总是私有成员,派生类对基类一般数据成员总是私有成员,派生类对基类的访问只
39、能间接进行。访问身份证号,应通的访问只能间接进行。访问身份证号,应通过过class Person中的公有成员函数(接口)中的公有成员函数(接口)GetNo()和和SetNo()进行进行:EGStud1.Employee.Person:SetNo(no);no=EGStud1.Employee.Person:GetNo();注意:注意:多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)Page 35计算机基础教研室计算机基础教研室 因为公有派生时,在派生类中不可以直接访问基类的私有因为公有派生时,在派生类中不可以直接访问基类的私有成员,但成员,但可以直接访问基类的保护成员可以直接访
40、问基类的保护成员,当需要在派生类中访问,当需要在派生类中访问基类的数据成员时,可以将它们定义为保护的,而不是私有的。基类的数据成员时,可以将它们定义为保护的,而不是私有的。 本例中类本例中类Circle为圆;类为圆;类Line为高;类为高;类Cone为圆锥,由为圆锥,由Circle和和Line公有派生而来。在公有派生而来。在Cone类中,类中,Circle和和Line类的类的接口完全不变,可以直接调用,这就是公有派生的优点。在接口完全不变,可以直接调用,这就是公有派生的优点。在Cone的成员函数中可直接访问的成员函数中可直接访问Circle和和Line中的公有成员和保中的公有成员和保护成员。护
41、成员。 检证检证主程序:主程序:圆类圆类Circle定义定义高类高类Line定义定义圆锥类圆锥类Cone定义定义【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥Page 36计算机基础教研室计算机基础教研室【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥class Circleprotected: float x,y,r; /(x,y)为圆心为圆心,r为半径为半径public: Circle(float a=0,float b=0,float R=0)x=a;y=b;r=R; void Setcoordinate(float a,float b)
42、x=a;y=b; /设置圆心坐标设置圆心坐标 void Getcoordinate(float &a,float &b)a=x;b=y; void SetR(float R)r=R;/设置半径设置半径 float GetR()return r;/取圆半径取圆半径 float GetAreaCircle()return float(r*r*3.14159); /取圆面积取圆面积 float GetCircumference()return float(2*r*3.14159); /取圆周长取圆周长;Page 37计算机基础教研室计算机基础教研室高类高类Line:class Lin
43、eprotected: float High;public: Line(float a=0)High=a; void SetHigh(float a)High=a; float GetHigh()return High;【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥Page 38计算机基础教研室计算机基础教研室class Cone:public Circle,public Linepublic: Cone(float a,float b,float R,float d):Circle(a,b,R),Line(d) float GetCV()return float(G
44、etAreaCircle()*High/3); /取得圆锥体积取得圆锥体积 float GetCA() /取得圆锥表面积取得圆锥表面积 return float(GetAreaCircle()+r*3.14159*sqrt(r*r+High*Hgih); /共有派生类中能直接访问直接基类的保护成员共有派生类中能直接访问直接基类的保护成员派生类圆锥:派生类圆锥:【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥Page 39计算机基础教研室计算机基础教研室int main()Cone c1(5,8,3,4);float a,b;cout圆锥体积圆锥体积:c1.GetCV()
45、n;cout圆锥表面积圆锥表面积:c1.GetCA()n;cout圆锥底面积圆锥底面积:c1.GetAreaCircle()n;cout圆锥底周长圆锥底周长:c1.GetCircumference()n;cout圆锥底半径圆锥底半径:c1.GetR()n;c1.Getcoordinate(a,b);cout圆锥底圆心坐标圆锥底圆心坐标:(a,b)n;cout圆锥高圆锥高:c1.GetHigh()n;return 0;检证主程序:检证主程序:【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥Page 40计算机基础教研室计算机基础教研室虚基类的引入:虚基类的引入:在图在图8
46、.4中,两个身份证号显然是不合理的。可以把中,两个身份证号显然是不合理的。可以把class Person这个共同基类设置为这个共同基类设置为虚基类虚基类,这样就仅有,这样就仅有一个一个Person基类成员,从不同路径继承来的同名数据基类成员,从不同路径继承来的同名数据成员(成员(身份证号身份证号)在内存中就是同一个数据。)在内存中就是同一个数据。 虚基类(选读)虚基类(选读)Page 41计算机基础教研室计算机基础教研室注意:注意:virtual 关键字只对紧随其后的基类名起作用关键字只对紧随其后的基类名起作用:class Student:virtual public Person.;clas
47、s Employee:virtual public Person.;虚基类虚基类(virtual base class)定义:定义:class 派生类名派生类名:virtual 访问限定符访问限定符 基类类名基类类名.;class 派生类名派生类名:访问限定符访问限定符 virtual 基类类名基类类名.;虚基类(选读)虚基类(选读)Page 42计算机基础教研室计算机基础教研室8.4 8.4 虚基类(选读)虚基类(选读)图图8.5 采用虚基类后在职研究生类储存图采用虚基类后在职研究生类储存图StudentGStudentEGStudentPersonStudent新成员新成员GStudent
48、新成员新成员PersonEmployee新成员新成员Person成员成员EGStudent新成员新成员PersonPersonEmployee这种继承称这种继承称为虚拟继承为虚拟继承虚拟继承:虚拟继承:在在Person的位置上放的是指针的位置上放的是指针,两个指针都指向两个指针都指向Person成员存储的内存成员存储的内存。这种继承称为。这种继承称为虚拟继承虚拟继承(virtual inheritance)。)。Page 43计算机基础教研室计算机基础教研室8.4 8.4 虚基类(选读)虚基类(选读)派生类名派生类名:派生类名派生类名( (参数总表参数总表):):基类名基类名1(1(参数名表参
49、数名表1)1), ,基类名基类名2(2(参数名表参数名表2),2),基类名基类名n(n(参数名表参数名表n)n), ,成成员对象名员对象名1(1(成员对象参数名表成员对象参数名表1),1),成员对象名成员对象名m(m(成成员对象参数名表员对象参数名表m)m),底层虚基类名底层虚基类名1(1(参数名表参数名表1)1), , 底层虚基类名底层虚基类名r(r(参数名表参数名表r)r) /派生类新增成员的初始化派生类新增成员的初始化; ; /所列出的成员对象名全部为新增成员对象的名字所列出的成员对象名全部为新增成员对象的名字在多层虚拟继承构造函数中,基类名不仅要列出直接基在多层虚拟继承构造函数中,基类
50、名不仅要列出直接基类,而且要列出底层虚基类,否则编译器认为出错。类,而且要列出底层虚基类,否则编译器认为出错。如如不是虚拟继承只能列直接基类。不是虚拟继承只能列直接基类。虚拟继承的构造函数:虚拟继承的构造函数:Page 44计算机基础教研室计算机基础教研室8.4 8.4 虚基类(选读)虚基类(选读)在派生类对象的在派生类对象的创建创建中:中:首先是虚基类的构造函数并按它们声明的顺序构造。首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构造函数按它们声明的顺序调用。第二批是非虚基类的构造函数按它们声明的顺序调用。第三批是成员对象的构造函数。第三批是成员对象的构造函数。最后是派生类
51、自己的构造函数被调用。最后是派生类自己的构造函数被调用。构造函数执行次序:构造函数执行次序:Page 45计算机基础教研室计算机基础教研室8.4 8.4 虚基类(选读)虚基类(选读)【例例8.3】在采用虚基类的多重继承中构造与析构的次序。在采用虚基类的多重继承中构造与析构的次序。class Objectpublic:Object()coutconstructor Objectn;Object()coutdeconstructor Objectn;class Bclass1public:Bclass1()coutconstructor Bclass1n;Bclass1()coutdeconstr
52、uctor Bclass1n;class Bclass2public:Bclass2()coutconstructor Bclass2n;Bclass2()coutdeconstructor Bclass2n;Page 46计算机基础教研室计算机基础教研室【例例8.3】在采用虚基类的多重继承中,构造与析构的次序。在采用虚基类的多重继承中,构造与析构的次序。class Bclass3public:Bclass3()coutconstructor Bclass3n;Bclass3()coutdeconstructor Bclass3n;class Dclass:public Bclass1,vir
53、tual Bclass3,virtual Bclass2 Object object;public: Dclass():object(),Bclass2(),Bclass3(),Bclass1() cout派生类建立派生类建立!n; Dclass()cout派生类析构派生类析构!n;int main() Dclass dd; cout“主程序运行主程序运行!n”;return 0;8.4 8.4 虚基类(选读)虚基类(选读)Page 47计算机基础教研室计算机基础教研室运行结果:运行结果:Constructor Bclass3/第一个虚拟基类第一个虚拟基类,与派生类析构函数排列无关与派生类析构
54、函数排列无关Constructor Bclass2/第二个虚拟基类第二个虚拟基类Constructor Bclass1/非虚拟基类非虚拟基类Constructor Object/对象成员对象成员派生类建立派生类建立!主程序运行主程序运行!派生类析构派生类析构!deconstructor Object/析构次序相反析构次序相反deconstructor Bclass1deconstructor Bclass2deconstructor Bclass3 /析构的次序与构造的次序相反。析构的次序与构造的次序相反。8.4 8.4 虚基类(选读)虚基类(选读)Page 48计算机基础教研室计算机基础教研
55、室对照图对照图8.5,尽管,尽管Employee和和Student的构造函的构造函数都包含数都包含Person的构造函数,但并未真正调用。的构造函数,但并未真正调用。唯一的一次调用是在唯一的一次调用是在EGStudent构造函数中构造函数中。如。如是非虚基类,则有两次调用。是非虚基类,则有两次调用。【例例8.4】虚基类在多层多重继承中的应用虚基类在多层多重继承中的应用 在职研究生类定义。在职研究生类定义。以虚基类定义公有派生的学生类以虚基类定义公有派生的学生类以虚基类定义公有派生的研究生类以虚基类定义公有派生的研究生类以虚基类定义公有派生的教职工类以虚基类定义公有派生的教职工类多重继承的以虚基
56、类定义多重继承的以虚基类定义公有派生的在职研究生类公有派生的在职研究生类8.4 8.4 虚基类(选读)虚基类(选读)Page 49计算机基础教研室计算机基础教研室class Student:public virtual Personstring NoStudent; /学号学号/30门课程与成绩略门课程与成绩略public:Student(string id, string name,Tsex sex,int birthday, string homeadd, string nostud);Student(); Student()cout析构析构Studentendl;void PrintSt
57、udentInfo(); ;Student:Student(string id, string name,Tsex sex, int birthday, string homeadd, string nostud) :Person(id,name,sex,birthday,homeadd) /注意注意Person参数名表不用类型参数名表不用类型cout构造构造Studentendl;NoStudent=nostud; 例例8.4 8.4 虚基类与在职研究生虚基类与在职研究生以虚基类定义公有派生的学生类:以虚基类定义公有派生的学生类:Page 50计算机基础教研室计算机基础教研室Student:
58、Student() /基类默认的无参数构造函数不必显式给出基类默认的无参数构造函数不必显式给出cout构造构造Studentendl;void Student:PrintStudentInfo()cout学号学号:NoStudentn;PrintPersonInfo();以虚基类定义公有派生的学生类:以虚基类定义公有派生的学生类: 例例8.4 8.4 虚基类与在职研究生虚基类与在职研究生Page 51计算机基础教研室计算机基础教研室class GStudent:public Student /以虚基类定义公有派生的研究生类以虚基类定义公有派生的研究生类 string NoGStudent; /
59、研究生号,其他略研究生号,其他略public: GStudent(string id, string name,Tsex sex,int birthday, string homeadd, string nostud,string nogstudent); /注意派生类构造函数声明方式注意派生类构造函数声明方式 GStudent(); GStudent()cout析构析构GStudentendl; void PrintGStudentInfo();GStudent:GStudent(string id, string name,Tsex sex, int birthday, string ho
60、meadd, string nostud, string nogstud): Student(id,name,sex,birthday,homeadd,nostud), Person(id,name,sex,birthday,homeadd) /因因Person是虚基类是虚基类,尽管不是直接基类尽管不是直接基类, Person必须出现。必须出现。 /不定义对象可不出现,为通用应出现。如不是虚基类,出现是错误的不定义对象可不出现,为通用应出现。如不是虚基类,出现是错误的 cout构造构造GStudentendl; NoGStudent=nogstud; 例例8.4 8.4 虚基类与在职研究生虚基类与在职研究生以
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年招商中介协议合同
- 2024年精神病解除劳动合同协议范本
- 2024年房屋租赁意向协议书
- 2024年指导股民短线理财服务协议书
- 2024年公司聘用协议书范本
- 2024年经济纠纷和解协议书
- 2024年软件开发技术人员保密协议
- 2024年厂房租赁合同协议
- 2024年企业咨询管理合作协议书范本
- 2024年老年人同居协议书
- 2024世界糖尿病日糖尿病与幸福感糖尿病健康教育课件
- 2024-2030年中国钾长石行业运行动态与产销需求预测报告
- 医学教材 超声引导下肩关节液压扩张联合针刀治疗肩周炎的临床应用
- 第四章-护理人际关系伦理
- 针灸室晕针应急预案演练方案
- 第2章 第5节 科学探究:电容器2023-2024学年新教材高二物理必修第三册同步课堂高效讲义配套教学设计(鲁科版2019)
- 电动汽车充电设施及场站测试评价规范第1部分:总则
- 二次系统安全防护事故应急预案格式(标准版)
- 餐饮技能大赛(中式面点师赛项)理论考试题及答案
- 2024年共青团入团积极分子考试题库(含答案)
- 籍贯对照表完整版
评论
0/150
提交评论