《类的继承和派生优秀PPT.ppt》由会员分享,可在线阅读,更多相关《类的继承和派生优秀PPT.ppt(111页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、类的继承和派生类的继承和派生第一页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类class Personstring IdPerson;/身份证号身份证号,18位数字位数字string Name;/姓名姓名bool Sex;/性别性别int Birthday;/格式格式1986年年8月月18日写作日写作19860818string HomeAddress;/家庭地址家庭地址public:Person(string,string,Tsex,int,string);/构造函数构造函数 Person();/默认的构造函数默认的构造函数 Person();
2、/析构函数析构函数第二页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类 void SetName(string);/修改名字修改名字 string GetName()return Name;/提取名字提取名字 void SetSex(Tsex sex)Sex=sex;/修改性别修改性别 bool GetSex()return Sex;/提取性别提取性别 void SetId(string id)IdPerson=id;/修改身份证号修改身份证号 string GetId()return IdPerson;/提取身份证号提取身份证号 void Set
3、Birth(int birthday)Birthday=birthday;/修改生日修改生日 int GetBirth()return Birthday;/提取生日提取生日 void SetHomeAdd(string);/修改住址修改住址 string GetHomeAdd()return HomeAddress;/提取住址提取住址 void PrintInfo();/打印个人信息打印个人信息;/接口函数:接口函数:第三页,本课件共有111页继承继承(inheritance)(inheritance):该机制是面向对象程序设计使代码可以复用的最重要的手段,该机制是面向对象程序设计使代码可以复
4、用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功它允许程序员在保持原有类特性的基础上进行扩展,增加功能。能。这样产生新的类,称派生类。继承呈现了面向对象程序这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构。设计的层次结构。体现了由简单到复杂的认识过程体现了由简单到复杂的认识过程。第八章第八章 继承与多态继承与多态多态性多态性(polymorphism):(polymorphism):多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于编译时的多数之
5、间的关系问题。函数的重载,运算符的重载,属于编译时的多态性。以虚函数为基础的运行时的多态性是面向对象程序设计的标态性。以虚函数为基础的运行时的多态性是面向对象程序设计的标志性特征。志性特征。体现了类推和比喻的思想方法。体现了类推和比喻的思想方法。第四页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类class Personstring IdPerson;/身份证号身份证号,18位数字位数字string Name;/姓名姓名bool Sex;/性别性别int Birthday;/格式格式1986年年8月月18日写作日写作19860818string H
6、omeAddress;/家庭地址家庭地址public:Person(string,string,Tsex,int,string);/构造函数构造函数 Person();/默认的构造函数默认的构造函数 Person();/析构函数析构函数第五页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类 void SetName(string);/修改名字修改名字 string GetName()return Name;/提取名字提取名字 void SetSex(Tsex sex)Sex=sex;/修改性别修改性别 Tsex GetSex()return Sex;
7、/提取性别提取性别 void SetId(string id)IdPerson=id;/修改身份证号修改身份证号 string GetId()return IdPerson;/提取身份证号提取身份证号 void SetBirth(int birthday)Birthday=birthday;/修改生日修改生日 int GetBirth()return Birthday;/提取生日提取生日 void SetHomeAdd(string);/修改住址修改住址 string GetHomeAdd()return HomeAddress;/提取住址提取住址 virtual void PrintInfo
8、();/打印个人信息打印个人信息;/接口函数:接口函数:第六页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类派生的学生类派生的学生类:class Student:public Person/定义派生的学生类定义派生的学生类 string NoStudent;/学号学号 course cs30;/30门课程与成绩门课程与成绩public:Student(string id,string name,Tsex sex,int birthday,string homeadd,string nostud);/注意派生类构造函数注意派生类构造函数声明方式声明方
9、式 Student();/默认派生类构造函数默认派生类构造函数 Student();/派生类析构函数派生类析构函数 SetCourse(string,int);/课程设置课程设置 int GetCourse(string);/查找成绩查找成绩 void PrintInfo();/打印学生情况打印学生情况;struct course string coursename;int grade;第七页,本课件共有111页第八章 继承与多态8.1继承与派生的概念继承与派生的概念 8.4虚基类虚基类(选读)(选读)8.3多重继承与派生类成员标识多重继承与派生类成员标识 8.6多态性与虚函数多态性与虚函数
10、8.5派生类应用讨论派生类应用讨论 8.2派生类的构造函数与析构函数派生类的构造函数与析构函数 第八页,本课件共有111页8.1 继承与派生的概念层次概念层次概念是计算机的重要概念。通过是计算机的重要概念。通过继承继承(inheritance)的)的机制可对类(机制可对类(class)分层,提供类型)分层,提供类型/子类型的关系。子类型的关系。C+通过通过类派生类派生(class derivation)的机制来支持继承。被)的机制来支持继承。被继承的类称为继承的类称为基类基类(base class)或)或超类超类(superclass),新的类),新的类为为派生类派生类(derived cla
11、ss)或)或子类子类(subclass)。)。基类和派生基类和派生类的集合称作类的集合称作类继承层次结构类继承层次结构(hierarchy)。)。如果基类和派生类共享相同的公有接口,则派生类被称作如果基类和派生类共享相同的公有接口,则派生类被称作基类的子类型(基类的子类型(subtype)。)。层次概念:层次概念:派生反映了事物之间的联系,事物的共性与个性之间的关系。派生反映了事物之间的联系,事物的共性与个性之间的关系。派派生与独立设计若干相关的类,前者工作量少,重复的部分可以从生与独立设计若干相关的类,前者工作量少,重复的部分可以从基类继承来,不需要单独基类继承来,不需要单独编程编程。第九页
12、,本课件共有111页8.1 继承与派生的概念8.1.1类的派生与继承类的派生与继承 8.1.2公有派生与私有派生公有派生与私有派生 第十页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类派生的学生类派生的学生类:class Student:public Person/定义派生的学生类定义派生的学生类 string NoStudent;/学号学号 course cs30;/30门课程与成绩门课程与成绩public:Student(string id,string name,Tsex sex,int birthday,string homeadd,str
13、ing nostud);/注意派生类构造函数声明方式注意派生类构造函数声明方式 Student();/默认派生类构造函数默认派生类构造函数 Student();/派生类析构函数派生类析构函数 SetCourse(string,int);/课程设置课程设置 int GetCourse(string);/查找成绩查找成绩 void PrintInfo();/打印学生情况打印学生情况;struct course string coursename;int grade;第十一页,本课件共有111页派生类的定义:派生类的定义:class 派生类名:访问限定符派生类名:访问限定符 基类名基类名1,访问限定
14、符,访问限定符 基类名基类名2,访问限定符,访问限定符 基类名基类名n private:成员表成员表1;/派生类增加或替代的私有成员派生类增加或替代的私有成员public:成员表成员表2;/派生类增加或替代的公有成员派生类增加或替代的公有成员protected:成员表成员表3;/派生类增加或替代的保护成员派生类增加或替代的保护成员;/分号不可少分号不可少其中基类其中基类1 1,基类,基类2 2,是已声明的类。是已声明的类。在派生类定义的类体中给出的成在派生类定义的类体中给出的成员称为员称为派生类成员派生类成员,它们是新增加成员,它们给派生类添加了不同于基类,它们是新增加成员,它们给派生类添加了
15、不同于基类的新的属性和功能。派生类成员也包括取代基类成员的更新成员。的新的属性和功能。派生类成员也包括取代基类成员的更新成员。8.1.1 8.1.1 类的派生与继承类的派生与继承第十二页,本课件共有111页基类基类1基类基类2基类基类n派生类派生类1派生类派生类2基类基类派生类派生类1派生类派生类2(a)多重继承)多重继承 (b)单继承)单继承 图图8.1多重继承与单继承多重继承与单继承 一个基类一个基类可以直接可以直接派生出多派生出多个派生类个派生类派生类可以派生类可以由多个基类由多个基类共同派生出共同派生出来,称多重来,称多重继承。继承。8.1.1 8.1.1 类的派生与继承类的派生与继承
16、多重继承:多重继承:如果一个派生类可以同时有多个基类,称为多重如果一个派生类可以同时有多个基类,称为多重继承(继承(multiple-inheritance),这时的派生类同时得到了多个),这时的派生类同时得到了多个已有类的特征。已有类的特征。单继承:单继承:派生类只有一个直接基类的情况称为单继承派生类只有一个直接基类的情况称为单继承(single-inheritance)。)。第十三页,本课件共有111页8.1.1 8.1.1 类的派生与继承类的派生与继承 在派生过程中,派生出来的新类同样可以作在派生过程中,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个为基类再继续派生
17、出更新的类,依此类推形成一个层次结构。直接参与派生出某类称为直接基类,而层次结构。直接参与派生出某类称为直接基类,而基类的基类,以及更深层的基类称为基类的基类,以及更深层的基类称为间接基类间接基类。类族:类族:同时一个基类可以直接派生出多个派生类。同时一个基类可以直接派生出多个派生类。这样形成了一个相互关联的类族。如这样形成了一个相互关联的类族。如MFC就是这就是这样的族类,它由一个样的族类,它由一个CObject类派生出类派生出200个个MFC类中的绝大多数。类中的绝大多数。多层次继承:多层次继承:第十四页,本课件共有111页编制编制派生派生类时类时可分可分四步四步 吸收基类的成员吸收基类的
18、成员 改造基类成员改造基类成员 发展新成员发展新成员重写构造函数与析构函数重写构造函数与析构函数 8.1.1 8.1.1 类的派生与继承类的派生与继承不论是数据成员,还是函数成员,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收除构造函数与析构函数外全盘接收 声明一个和某基类成员同名的新成员声明一个和某基类成员同名的新成员,派生类中派生类中的新成员就屏蔽了基类同名成员称为的新成员就屏蔽了基类同名成员称为同名覆盖同名覆盖(override)派生类新成员必须与基类成员不同名,它的加派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。入保证派生类在功能上有所发展。派生编
19、程步骤:派生编程步骤:第十五页,本课件共有111页8.1.1 8.1.1 类的派生与继承类的派生与继承第二步中,第二步中,新成员如是成员函数,参数表也必须一样新成员如是成员函数,参数表也必须一样,否则是重,否则是重载。载。第三步中,独有的新成员才是继承与派生的核心特征。第三步中,独有的新成员才是继承与派生的核心特征。第四步是重写构造函数与析构函数,派生类不继承这两种函数。第四步是重写构造函数与析构函数,派生类不继承这两种函数。不管原来的函数是否可用不管原来的函数是否可用一律重写可免出错一律重写可免出错(?)。访问控制:访问控制:亦称为亦称为继承方式继承方式,是对基类成员进一步的限制。访问控制也
20、是三,是对基类成员进一步的限制。访问控制也是三种:种:公有(公有(public)方式,亦称公有继承)方式,亦称公有继承保护(保护(protected)方式,亦称保护继承)方式,亦称保护继承私有(私有(private)方式,)方式,亦称私有继承。亦称私有继承。第十六页,本课件共有111页8.1.2 8.1.2 公有派生与私有派生公有派生与私有派生访问限定符两方面含义:访问限定符两方面含义:派生类成员(新增成员)函数对基类派生类成员(新增成员)函数对基类(继承来的)成员的访问(调用和操作)(继承来的)成员的访问(调用和操作),和,和从派生类对象之从派生类对象之外对派生类对象中的基类成员的访问外对派
21、生类对象中的基类成员的访问。class Student:public Person public:Student(string id,string name,Tsex sex,int birthday,string homeadd,string nostud);class Person private:string Name;/姓名姓名public:string GetName()return Name;/提取名字提取名字第十七页,本课件共有111页8.1.2 8.1.2 公有派生与私有派生公有派生与私有派生不可直接访问 不可直接访问 private 不可直接访问 private protec
22、ted 不可直接访问 private public 私有派生 不可直接访问 不可直接访问 private 不可直接访问 protected protected 可直接访问 public public 公有派生 在派生类对象外访问派生类对象的基类成员 在派生类中对基类成员的访问限定 基类中的访问限定 派生方式 公有派生是绝对主流公有派生是绝对主流。第十八页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类/注意注意Person参数表不用类型参数表不用类型Student:Student(string id,string name,Tsex sex,int
23、birthday,string homeadd,string nostud):Person(id,name,sex,birthday,homeadd)NoStudent=nostud;for(int i=0;i30;i+)/课程与成绩清空课程与成绩清空 csi.coursename=#;csi.grade=0;派生类构造函数派生类构造函数:第十九页,本课件共有111页派生类构造函数的定义:派生类构造函数的定义:派生类名派生类名:派生类名(参数总表)派生类名(参数总表):基类名基类名1(参数名表(参数名表1),基类名基类名2(参数名表(参数名表2),),基类名,基类名n(参数名表(参数名表n),
24、成员对象名成员对象名1(成员对象参数名表(成员对象参数名表1),),成员对象名,成员对象名m(成员对象参数名表(成员对象参数名表m)/派生类新增成员的初始化;派生类新增成员的初始化;/所列出的成员对象名全部为新增成员对象的名字所列出的成员对象名全部为新增成员对象的名字注意:注意:在构造函数的声明中,冒号及冒号以后部分必须略去。在构造函数的声明中,冒号及冒号以后部分必须略去。所谓不能继承并不是不能利用,而是把基类的构造函数作为新的所谓不能继承并不是不能利用,而是把基类的构造函数作为新的构造函数的一部分,或者讲调用基类的构造函数。构造函数的一部分,或者讲调用基类的构造函数。基类名仅指直接基类名仅指
25、直接基类,写了底层基类,编译器认为出错基类,写了底层基类,编译器认为出错。冒号后的基类名,成员对象名的次序可以随意,这里的次序冒号后的基类名,成员对象名的次序可以随意,这里的次序与调用次序无关。与调用次序无关。8.2 8.2 派生类的构造函数与析构函数派生类的构造函数与析构函数第二十页,本课件共有111页派生类构造函数各部分执行次序:派生类构造函数各部分执行次序:1.1.调用基类构造函数,按它们在派生类定义的调用基类构造函数,按它们在派生类定义的先后顺序,顺序调用。先后顺序,顺序调用。2.2.调用成员对象的构造函数,按它们在类定义调用成员对象的构造函数,按它们在类定义中声明的先后顺序,顺序调用
26、。中声明的先后顺序,顺序调用。3.3.派生类的构造函数体中的操作。派生类的构造函数体中的操作。8.2 8.2 派生类的构造函数与析构函数派生类的构造函数与析构函数注意:注意:在派生类构造函数中,只要基类不是使用无参的默认构在派生类构造函数中,只要基类不是使用无参的默认构造函数都要显式给出基类名和参数表造函数都要显式给出基类名和参数表。如果基类没有定义构造函数,则派生类也可以不定义,如果基类没有定义构造函数,则派生类也可以不定义,全部采用系统给定的默认构造函数。全部采用系统给定的默认构造函数。如果基类定义了带有形参表的构造函数时,派生类就应当定义如果基类定义了带有形参表的构造函数时,派生类就应当
27、定义构造函数。构造函数。第二十一页,本课件共有111页8.2 8.2 派生类的构造函数与析构函数派生类的构造函数与析构函数析构函数:析构函数:析构函数析构函数的功能是作善后工作。的功能是作善后工作。只要在函数体内把派生类新增一般成员处理好只要在函数体内把派生类新增一般成员处理好就可以了就可以了,而,而对新增的成员对象和基类的善后工作,系对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成统会自己调用成员对象和基类的析构函数来完成。析构函数各部分执行次序与构造函数相反,析构函数各部分执行次序与构造函数相反,首首先对派生类新增一般成员析构,然后对新增对象成员析先对派生类新
28、增一般成员析构,然后对新增对象成员析构,最后对基类成员析构构,最后对基类成员析构。第二十二页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类【例例8.1】由在册人员类公有派生学生类。我们希望基类和派生类共享相同由在册人员类公有派生学生类。我们希望基类和派生类共享相同的公有接口的公有接口,只能采用公有派生来实现。只能采用公有派生来实现。基类:基类:enum Tsex mid,man,woman;class Personstring IdPerson;/身份证号身份证号,18位数字位数字string Name;/姓名姓名Tsex Sex;/性别性别int
29、 Birthday;/格式格式1986年年8月月18日写作日写作19860818string HomeAddress;/家庭地址家庭地址public:Person(string,string,Tsex,int,string);/构造函数构造函数 Person();/默认的构造函数默认的构造函数 Person();/析构函数析构函数第二十三页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类void SetName(string);/修改名字修改名字string GetName()return Name;/提取名字提取名字void SetSex(Tsex
30、 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;/提取生日提取生日void SetHomeAdd(string);/修改住址修改住址string GetHomeAdd()return Home
31、Address;/提取住址提取住址virtual void PrintInfo();/输出个人信息输出个人信息 ;/接口函数:接口函数:第二十四页,本课件共有111页【例例8.18.1】由在册人员类公有派生学生类由在册人员类公有派生学生类派生的学生类派生的学生类:class Student:public Person/定义派生的学生类定义派生的学生类 string NoStudent;/学号学号 course cs30;/30门课程与成绩门课程与成绩public:Student(string id,string name,Tsex sex,int birthday,string homeadd
32、,string nostud);/注意注意派生类构造函数派生类构造函数声明方式声明方式 Student();/默认派生类构造函数默认派生类构造函数 Student();/派生类析构函数派生类析构函数 SetCourse(string,int);/课程设置课程设置 int GetCourse(string);/查找成绩查找成绩 void PrintInfo();/打印学生情况打印学生情况;struct course string coursename;int grade;验证验证主函数主函数第二十五页,本课件共有111页8.2 8.2 派生类的构造函数与析构函数派生类的构造函数与析构函数注意:注
33、意:本例中标准本例中标准C+字符串字符串string是作为成员对象使用的(是作为成员对象使用的(聚聚合合),动态内存分配的构造和析构被封装起来,使用十分简单。如),动态内存分配的构造和析构被封装起来,使用十分简单。如使用动态生成的使用动态生成的C风格字符串,要考虑深复制,那要复杂得多。风格字符串,要考虑深复制,那要复杂得多。提倡完善的类对象封装,不仅封装数据和对数据的操作,提倡完善的类对象封装,不仅封装数据和对数据的操作,而且封装资源的动态分配与释放,形成一个完备的子系统。在而且封装资源的动态分配与释放,形成一个完备的子系统。在一个有层次结构的类体系中资源的动态分配与释放应封装在成一个有层次结
34、构的类体系中资源的动态分配与释放应封装在成员对象中员对象中,如同使用标准的,如同使用标准的string字符串类那样。字符串类那样。聚合是一种完善的封装。采用成员对象将大大简化层次聚合是一种完善的封装。采用成员对象将大大简化层次结构的类体系中资源的动态分配与释放的处理方法,不再出结构的类体系中资源的动态分配与释放的处理方法,不再出现难度极大的多层次的深复制。现难度极大的多层次的深复制。第二十六页,本课件共有111页8.3 8.3 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)由多个基类共同派生出新的派生类,这样的继承结构被称为多由多个基类共同派生出新的派生类,这样的继承结构被称
35、为多重继承或多继承(重继承或多继承(multiple-inheritance)椅子椅子床床沙发沙发(单继承单继承)躺椅躺椅(多重继承多重继承)两用沙发两用沙发(多重继承多重继承)图图8.2椅子,床到两用沙发椅子,床到两用沙发多重继承实例:多重继承实例:第二十七页,本课件共有111页在册人员在册人员学生学生(单继承单继承)教职工教职工(单继承单继承)兼职教师兼职教师(单继承单继承)教师教师(单继承单继承)行政人员行政人员(单继承单继承)工人工人(单继承单继承)研究生研究生(单继承单继承)行政人员兼教师行政人员兼教师(多重继承多重继承)在职研究生在职研究生(多重继承多重继承)研究生助教研究生助教(
36、多重继承多重继承)图图8.3大学在册人员继承关系大学在册人员继承关系8.3 8.3 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)派生出来的派生出来的新类同样可新类同样可以作为基类以作为基类再继续派生再继续派生出更新的类,出更新的类,依此类推形依此类推形成一个成一个层次层次结构结构。第二十八页,本课件共有111页8.3 8.3 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)歧义性问题歧义性问题:参见图参见图8.3,比如行政人员兼教师,在其基类教师中有一个,比如行政人员兼教师,在其基类教师中有一个“教教职工编号职工编号”,另一基类行政人员中也有一个,另一基类行
37、政人员中也有一个“教职工编号教职工编号”,如果只讲教职工编号那么是哪一个基类中的呢?这两者可能是如果只讲教职工编号那么是哪一个基类中的呢?这两者可能是一回事,但一回事,但计算机系统并不这么认为计算机系统并不这么认为。进一步,如果进一步,如果“教职工编号教职工编号”是由两个基类是由两个基类“教师教师”和和“行政行政人员人员”共同的基类共同的基类“教职工教职工”类继承来的,只有同一个标识符,类继承来的,只有同一个标识符,也不能用改标识符来区分。也不能用改标识符来区分。唯一标识问题:唯一标识问题:通常采用作用域分辨符通常采用作用域分辨符“:”:基类名基类名:成员名成员名;/数据成员数据成员基类名基类
38、名:成员名(参数表)成员名(参数表);/函数成员函数成员 第二十九页,本课件共有111页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类对象类对象EGStudent1,并假,并假定派生全部为公有派生,定派生全部为公有派生,而而intNo全为公全为公有成员有成
39、员:EGStud1.No/在职学号在职学号EGStud1.GStudent:No/研究生号研究生号EGStud1.GStudent.Student:No/学生号学生号EGStud1.GStudent.Student.Person:No/身份证号身份证号EGStud1.Employee:No/工作证号工作证号EGStud1.Employee.Person:No/身份证号身份证号两个身份证号从逻辑上讲两个身份证号从逻辑上讲应是一回事应是一回事,但是物理上是但是物理上是分配了不同内存空间,是分配了不同内存空间,是两个变量,请参见图两个变量,请参见图8.4(b)。第三十页,本课件共有111页Perso
40、n Person StudentEmployeeGStudent EGStudentPerson成员成员Person成员成员 Student新成员新成员 GStudent新成员新成员 Employee新成员新成员 EGStudent新成员新成员 图图8.4(b)在职研究生)在职研究生派生类存储图派生类存储图 建议采用有确定字面意思的标识符,它可以被编译器简单区分出来。建议采用有确定字面意思的标识符,它可以被编译器简单区分出来。如如果果classPerson的身份证号标识为的身份证号标识为intIdPerson,则写为:,则写为:EGStud1.GStudent:IdPersonEGStud1.
41、Employee:IdPerson不必标出那么多层次的类,但写不必标出那么多层次的类,但写EGStud1.IdPerson是错的。是错的。作用域分辨符不能嵌套使用作用域分辨符不能嵌套使用,如:,如:EGStud1.GStudent:Student:No/学生号学生号EGStud1.GStudent:Student:Person:No/身份证号身份证号是是错误错误的。的。8.3 8.3 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)第三十一页,本课件共有111页8.3 8.3 多重继承与派生类成员标识(选读)多重继承与派生类成员标识(选读)一般数据成员总是私有成员,派生类对基类
42、的访一般数据成员总是私有成员,派生类对基类的访问只能间接进行。访问身份证号,应通过问只能间接进行。访问身份证号,应通过class class PersonPerson中的公有成员函数(接口)中的公有成员函数(接口)GetNo()GetNo()和和SetNoSetNo()()进行:进行:EGStud1.Employee.Person:SetNo(intno);no=EGStud1.Employee.Person:GetNo();注意:注意:第三十二页,本课件共有111页【例例8.2】由圆和高多重继承派生出圆锥。由圆和高多重继承派生出圆锥。因为公有派生时,在派生类中不可以直接访问基类的私有成员,因
43、为公有派生时,在派生类中不可以直接访问基类的私有成员,但但可以直接访问基类的保护成员可以直接访问基类的保护成员,当需要在派生类中访问基类的数,当需要在派生类中访问基类的数据成员时,可以将它们定义为保护的,而不是私有的。据成员时,可以将它们定义为保护的,而不是私有的。本例中类本例中类Circle为圆;类为圆;类Line为高;类为高;类Cone为圆锥,由为圆锥,由Circle和和Line公有派生而来。在公有派生而来。在Cone类中,类中,Circle和和Line类的接口完全不类的接口完全不变,可以直接调用,这就是公有派生的优点。在变,可以直接调用,这就是公有派生的优点。在Cone的成员函数中可的成
44、员函数中可直接访问直接访问Circle和和Line中的公有成员和保护成员。中的公有成员和保护成员。【例例8.28.2】由圆和高多重继承派生出圆锥由圆和高多重继承派生出圆锥检证检证主程序:主程序:圆类圆类Circle定义定义高类高类Line定义定义圆锥类圆锥类Cone定义定义第三十三页,本课件共有111页虚基类的引入:虚基类的引入:在图在图8.4中,两个身份证号显然是不合理的。可以把中,两个身份证号显然是不合理的。可以把class Person这个共同基类设置为这个共同基类设置为虚基类虚基类,这样就仅有一个,这样就仅有一个Person基类成员,从不同路径继承来的同名数据成员(基类成员,从不同路径
45、继承来的同名数据成员(身身份证号份证号)在内存中就是同一个数据。)在内存中就是同一个数据。8.4 8.4 虚基类(选读)虚基类(选读)注意:注意:virtual 关键字只对紧随其后的基类名起作用关键字只对紧随其后的基类名起作用:class Student:virtual public Person.;class Employee:virtual public Person.;虚基类虚基类(virtualbaseclass)定义:定义:class 派生类名派生类名:virtual 访问限定符访问限定符 基类类名基类类名.;class 派生类名派生类名:访问限定符访问限定符 virtual 基类类
46、名基类类名.;第三十四页,本课件共有111页8.4 8.4 虚基类(选读)虚基类(选读)图图8.5采用虚基类后在职研究生类储存图采用虚基类后在职研究生类储存图StudentGStudentEGStudentPersonStudent新成员新成员GStudent新成员新成员PersonEmployee新成员新成员Person成员成员EGStudent新成员新成员PersonPersonEmployee这种继承称这种继承称为虚拟继承为虚拟继承虚拟继承:虚拟继承:在在Person的位置上放的是指针的位置上放的是指针,两个指针都指向两个指针都指向Person成员存储的内存成员存储的内存。这种继承称为。
47、这种继承称为虚拟继承虚拟继承(virtualinheritance)。)。第三十五页,本课件共有111页8.4 8.4 虚基类(选读)虚基类(选读)派生类名派生类名:派生类名派生类名(参数总表参数总表):):基类名基类名1(1(参数名表参数名表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)
48、r)/派生类新增成员的初始化派生类新增成员的初始化;/所列出的成员对象名全部为新增成员对象的名字所列出的成员对象名全部为新增成员对象的名字在多层虚拟继承构造函数中,基类名不仅要列出直在多层虚拟继承构造函数中,基类名不仅要列出直接基类,而且要列出底层虚基类,否则编译器认为接基类,而且要列出底层虚基类,否则编译器认为出错。出错。虚拟继承的构造函数:虚拟继承的构造函数:第三十六页,本课件共有111页8.4 8.4 虚基类(选读)虚基类(选读)在派生类对象的在派生类对象的创建创建中:中:首先是虚基类的构造函数并按它们声明的顺序构造。首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构造函
49、数按它们声明的顺序调用。第二批是非虚基类的构造函数按它们声明的顺序调用。第三批是成员对象的构造函数。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用。最后是派生类自己的构造函数被调用。构造函数执行次序:构造函数执行次序:第三十七页,本课件共有111页8.4 8.4 虚基类(选读)虚基类(选读)【例例8.3】在采用虚基类的多重继承中,在采用虚基类的多重继承中,构造与析构的次序。构造与析构的次序。class Dclass:public Bclass1,virtual Bclass3,virtual Bclass2 Object object;public:Dclass():object
50、(),Bclass2(),Bclass3(),Bclass1()cout派生类建立派生类建立!n;Dclass()cout派生类析构派生类析构!n;void main()Dclass dd;cout主程序运行主程序运行!n;第三十八页,本课件共有111页运行结果:运行结果:Constructor Bclass3/第一个虚拟基类第一个虚拟基类,与派生类析构函数排列无关与派生类析构函数排列无关Constructor Bclass2/第二个虚拟基类第二个虚拟基类Constructor Bclass1/非虚拟基类非虚拟基类Constructor Object/对象成员对象成员派生类建立派生类建立!主程