程序设计基础第9章(08级).ppt_第1页
程序设计基础第9章(08级).ppt_第2页
程序设计基础第9章(08级).ppt_第3页
程序设计基础第9章(08级).ppt_第4页
程序设计基础第9章(08级).ppt_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

1、0,第9章 继承和派生,9.1 继承与派生的基本概念 9.2 派生类的继承方式和访问属性 9.3 派生类的构造函数和析构函数 9.4 多重继承的二义性 9.5 虚基类,1,9.1 继承与派生的基本概念,9.1.1基本概念 抽象具有层次性。 从一个或多个以前定义的类(基类)产生新类的过程称为派生,这个新类又称为派生类。 类的继承(inheritance)是指新类从基类那里得到基类的特征,也就是继承基类的数据和函数(功能)。 派生的新类同时也可以增加或重新定义数据和操作,这就产生了类的层次性。 派生就是创建一个既具有被继承类的属性和行为,又具有新类自己特有属性和行为的新类的能力。派生和继承的概念也

2、来自于人们认识客观世界的过程。,2,继承与派生的机制与功能是实现代码重用。 当从现存类中派生出新类时,可以对派生类做如下几种变化: 可以增加新的数据成员; 可以增加新的成员函数; 可以重新定义已有的成员函数; 可以改变现有成员的属性。,3,9.1.2 派生类,一、派生类的声明格式 class 派生类名:继承方式 基类名1, 继承方式 基类名2 , ,继承方式 基类名n private: 成员表1; /派生类增加或替代的私有成员 public: 成员表2; /派生类增加或替代的公有成员 protected: 成员表3; /派生类增加或替代的保护成员 ;,4,多重继承,单继承,5,二、派生类的构成

3、,1、从基类接收的成员 2、派生类对基类的扩充(添加的新成员) 3、派生类对基类成员的改造,即与基类某些成员名相同,但作用不同的成员函数. 被改造的成员将覆盖原有的成员,即原有成员函数的功能由新的功能代替 注意:构造函数与析构函数不被继承(传递),6,9.2 派生类的继承方式,7,一、公有继承(public),公有继承的派生类成员访问属性特点: 1、基类公有成员还是派生类中的公有成员 2、基类保护成员还是派生类中的保护成员 3、基类私有成员在派生类中不可直接访问,8,例9.1:公有继承(public).演示公有继承中派生类对基类成员的访问,#include #include /基类 class

4、 Person/人员类定义 protected: char Name10;/姓名 intAge;/年龄 charSex;/性别 public: void Register(char *name, int age, char sex) ; void ShowMe(); ;,9,void Register(char *name, int age, char sex) strcpy(Name, name); Age = age; Sex = (sex = m?m:f); void ShowMe() cout Name t Age t Sex endl; ;,10,/派生类 class Employe

5、e: public Person /雇员类定义 char Dept20;/工作部门 float Salary; /月薪 public: Employee() ; void EmployeeRegister(char *name, int age, char sex, char *dept, float salary); void ShowEmp(); /显示雇员信息 ;,11,void EmployeeRegister (char *name, int age, char sex char *dept, float salary) strcpy(Dept, dept); Salary = sa

6、lary; Register(name, age, sex); /派生类成员函数直接使用基类的公有成员 void ShowEmp( ) ShowMe();/直接使用基类的公有成员 cout Dept t Salary t; ;,12,int main() Employee E; E. EmployeeRegister (“张三”,18,m ,“计算机销售”,1500 ); E.ShowMe(); /派生类对象直接使用基类的公有成员 E.ShowEmp(); return 0; ,13,二、私有继承(public),私有继承的派生类成员的访问属性特点 : 1.基类的公有成员和保护成员都是派生类的

7、私有成员 2.对于基类的私有成员,无论派生类内部成员,或派生类使用者,或派生类对象都无法直接访问 ,即在派生类中或派生类外都无法直接访问基类的私有成员,14,三、保护继承(public),保护继承方式继承的派生类成员的访问属性特点 : 1.基类的公有成员和保护成员都是派生类的保护成员,派生类可以通过自身的成员函数或其子类的成员函数访问他们 2.对于基类的私有成员,无论是派生类内部成员或派生类使用者都无法直接访问,15,例9.2 保护继承中派生类对基类成员的访问。,#include #include using namespace std; class Person protected: cha

8、r Name20; char Sex; int Age; public: void Register(char *name, int age, char sex) strcpy(Name, name); Age = age; Sex = (sex = m?m:f); void ShowMe() cout Name t Age t Sex endl; ;,16,class Student : protected Person int Number; char ClassName10; public: void Register(char *classname, int number, char

9、*name, int age, char sex) /修改基类同名成员 strcpy(ClassName, classname); Number = number; strcpy(Name, name);/正确,引用基类的保护成员 Age = age;/正确,引用基类的保护成员 Sex = (sex = m?m:f); /正确,引用基类的保护成员 ,17,voidShowStu() cout Number t ClassName t; ShowMe(); /调用被继承来的成员函数 ; int main() Student stu; stu.Register(“计算机51”,85071011,“

10、张三,18,m); stu.ShowStu(); stu.ShowMe();/错误,对象不能访问保护成员 return 0; ,18,9.3 派生类的构造函数和析构函数,一、派生类构造函数的一般形式: 派生类名:;派生类名(参数总表):基类名1(参数表1),基类名n(参数表n), 内嵌对象名1(对象参数表1), ,内嵌对象名m(对象参数表m) 派生类新增加成员的初始化; ,19,二、派生类构造函数各部分的执行次序 1.调用基类构造函数,按它们在派生类继承方式描述的先后顺序调用。 2.调用内嵌对象构造函数,调用次序按各个对象在派生类内声明的顺序。 3.派生类的构造函数体中的操作. 三、派生类析构

11、函数 派生类析构函数执行过程与构造函数执行过程相反。 1.执行派生类析构函数 2.执行内嵌对象的析构函数 3.执行基类析构函数,20,例9.3 派生类构造函数和析构函数,#include #include using namespace std; class Person charName10; /姓名 int Age;/年龄 public: Person(char* name,int age) strcpy(Name, name);Age = age; coutconstructor of personNameendl; Person() coutdeconstrutor of person

12、Nameendl; ;,21,class Student : public Person char ClassName10; /班级 PersonMonitor; /班长 public: Student(char *name, int age, char *classname, char *name1, int age1) : Person(name, age) , Monitor(name1, age1) strcpy(ClassName, classname); coutconstructor of Student endl; Student() coutdeconstrucor of S

13、tudent endl; ; int main() Student stu(“张三”,18,“计算机51”,“李四,20); return 0; ,22,9.4多重继承的二义性,所谓二义性是指对于一个概念、变量、表达式、函数等有两种或两种以上的解释。 在类的派生层次结构中,基类的成员和派生类的新增成员都具有类作用域,基类成员既在基类中存在和有效,并且在派生类中存在;派生类的新增成员仅在派生类中存在和有效。 当派生类中有与基类同名的新成员(成员函数必须参数的类型、排列、个数都相同,否则属于函数重载),这时派生类的同名新成员,将将覆盖基类同名成员,即使用派生类的对象只能访问到派生类中的同名新成员,

14、无法访问基类的同名成员。 要访问基类的同名成员,必须用下面格式访问: 基类名:数据成员名 或 基类名:成员函数名(参数表),23,多继承中的二义性,派生类B1中有6个成员,但只有两个名,使用“对象名.成员”访问只能访问B1的同名成员。,派生类B2中有4个成员,但只有两个名,使用“对象名.成员”访问有二义性。,24,例9.4多继承二义性 # include “iostream.h” class A1 public: int v; void fun( )cout“ A1类成员:v=”vendl; ; class A2 public: int v; void fun( )cout“ A2类成员:v=

15、”vendl; ;,25,class B1:public A1,public A2 public: int v; void fun( )cout“ B1类成员:v=”vendl; ; class B2:public A1,public A2 ; void main( ) B1 b1; B2 b2; b1.v=1; b1.fun( ); b1.A1:v=11; b1.A1:fun( ); b2.A1:v=21; b2.A1:fun( ); b1.A2:v=12; b1.A2:fun( ); b2.A2:v=22; b2.A2:fun( ); ,26,多层多继承中的二义性 当从一个基类派生出多个派

16、生类,再由这些派生类再多重派生出新的派生类时,会出现成员的二义性。,27,例9.5多层多继承二义性 # include “iostream.h” class A /最高层基类 public: int Av; void Afun( )cout“ A类成员:Av=”Avendl; ; class B1:public A /第二层基类 public: int B1v; ; class B2:public A /第二层基类 public: int B2v; ;,28,class C:public B1,public B2 public: int Cv; void Cfun( )cout“ C类成员:C

17、v=”Cvendl; ; void main( ) C c1; c1.Cv=0; c1.Cfun( ); c1.B1:Av=10; c1.B2:Av=20; c1.B1:Afun( ); c2.B2:Afun( ); 从输出结果可见,Av成员有两个拷贝。然而通常情况下,派生类中只需要一份间接基类的成员就可以了。,程序结果: C类成员:Cv=0 A类成员:Av=10 A类成员:Av=20,29,9.5虚基类,9.5.1虚基类的概念 在多层多继承中,新的派生类可能从间接基类继承某些成员的多份拷贝,即出现间接基类的同名数据成员多个,同名函数成员多个。通常这些同名成员只需要一个,其余是多余的。 C+通

18、过虚基类派生机制来解决此问题,使得在经过多层多继承之后,新派生类从间接基类继承来的每个同名成员就只有一个拷贝,访问也避免了二义性。 虚基类的声明方法: class 派生类名:virtual 继承方式 基类 在多继承情况下,虚基类关键字的作用范围与继承方式关键字相同,30,对例9.5中的情况,在派生B1、B2时,使用虚基类继承。,virtual,virtual,31,# include “iostream.h” class A /最高层基类 public: int Av; void Afun( )cout“ A类成员:Av=”Avendl; ; class B1:virtual public A

19、 /第二层虚基类 public: int B1v; ; class B2: virtual public A /第二层虚基类 public: int B2v; ;,32,class C:public B1,public B2 public: int Cv; void Cfun( )cout“ C类成员:Cv=”Cvendl; ; void main( ) C c1; c1.Cv=0; c1.Cfun( ); c1.Av=10; /原来是c1.B1:Av=10; c1.Afun( ); /原来是c1.B1:Afun( ); 对于派生类C类的成员Av、Afun()如同直接从间接基类A类继承而来,其

20、基类B1、B2如同没有。 作为A的派生类,B1、B2类并不受到virtual的影响。,程序结果: C类成员:Cv=0 A类成员:Av=10,33,9.5.2虚基类构造函数,如果基类A定义有非默认构造函数,并且没有重载默认形式的构造函数,在多层多继承结构中,直接或间接继承虚基类的所有派生类,都必须定义构造函数,并且要在构造函数的成员初始化列表中列出对虚基类的初始化。在上例中加入非默认构造函数。 # include “iostream.h” class A /最高层基类 public: int Av; A(int a) Av=a; void Afun( )cout“ A类成员:Av=”Avendl

21、; ; class B1:virtual public A /第二层虚基类 public: B1(int b):A(b) /构造函数 int B1v; ;,34,class B2: virtual public A /第二层虚基类 public: B2(int b):A(b) /构造函数 int B2v; ; class C:public B1,public B2 public: int Cv; C( int c):A(c),B1(c),B2(c) void Cfun( )cout“ C类成员:Cv=”Cvendl; ; void main( ) C c1(10); c1.Afun( ); ,

22、35,程序设计举例,例9.4 从Point类继承的Circle类 / Point.h文件 Point类的声明 #ifndef POINT_H #define POINT_H class Point int x, y;/点的x和y坐标 public: Point( int = 0, int = 0 ); / 构造函数 void SetPoint( int, int ); / 设置坐标 int GetX() return x; / 取x坐标 int GetY() return y; / 取y坐标 void Print();/输出点的坐标 ; #endif,36,/ Point.cpp文件 Poin

23、t类的成员函数定义,#include #include point.h Point:Point( int a, int b ) SetPoint( a, b ); /构造函数 void Point:SetPoint( int a, int b ) x = a; y = b; void Point:Print() cout x , y ; ,37,/ Circle.h文件 Circle类的声明,#ifndef CIRCLE_H #define CIRCLE_H #include #include point.h class Circle : public Point double radius;

24、 public: Circle(int x = 0, int y = 0 , double r = 0.0); void SetRadius( double ); /设置半径 double GetRadius();/取半径 double Area();/计算面积 void Print();/输出圆心坐标和半径 ; #endif,38,/ Circle.cpp文件 Circle类的成员函数定义,#include #include circle.h Circle:Circle(int a,int b,double r): Point(a,b) SetRadius( r ); void Circle

25、:SetRadius( double r ) radius = ( r = 0 ? r : 0 ); double Circle:GetRadius() return radius; double Circle:Area() return 3.14159 * radius * radius; void Circle:Print() cout Center = ; Point:Print(); cout ; Radius = radius endl; ,39,/ Example10-5.cpp文件: Circle Demo,#include “iostream.h” #include point

26、.h #include circle.h int main( ) Point p(30,50); Circle c(120,80,10.0); cout Point p: ; p.Print(); cout nCircle c: ; c.Print(); cout The centre of circle c: ; c.Point:Print(); cout nThe area of circle c: c.Area() endl; return 0; ,40,例9.5 一个基类有多个派生类。定义了一个基类(Person)及其两个派生类(Teacher)和(Student)。,#include

27、 #include class Person /基类的定义 protected: char Name10; char Sex; int Age; public: void Register(char *name,int age,char sex); void ShowMe( ); ;,41,void Person:Register(char *name,int age,char sex) strcpy(Name, name); Sex= (sex=m? m: f ); Age = age; void Person:ShowMe() cout 姓 名:Nameendl; cout 性 别:(Se

28、x=m?男:女)endl; cout 年 龄:Ageendl; ,42,class Teacher: public Person /派生类Teacher的定义 char Dept20; int Salary; public: Teacher(char *name,int age,char sex,char *dept,int salary); void ShowMe() Person:ShowMe(); cout 工作单位:Deptendl; cout 月 薪:Salaryendlendl; ; Teacher:Teacher(char *name,int age,char sex,char

29、*dept,int salary) Register(name,age,sex); strcpy(Dept, dept); Salary = salary; ,43,class Student : public Person /派生Student类的定义 char ID12; char Class12; public: Student(char *name,int age,char sex, char *id,char *classid); void ShowMe( ) cout 学 号:IDendl; Person:ShowMe(); /使用基类的同名成员函数 cout 班 级:Classn

30、n; ; Student:Student(char *name,int age,char sex,char *id,char *classid) Register(name,age,sex); strcpy(ID, id); strcpy(Class, classid); ,44,int main() Teacher emp1(章立早,38,m,电信学院,2300); Student std1(李木子,22,f,02035003,能动01); emp1.ShowMe( ); std1.ShowMe( ); return 0; ,45,例9.6多重继承,从多个基类派生出来的类。,/ 基类base1.h文件 #ifndef BASE1_H #define BASE1_H class Base1 int value; public: Base1( int x ) value = x; int getData() const return value; ; #endif,46,/基类 base2.h文件,#ifndef BASE2_H #define BASE2_H class Base2 char letter; public: Bas

温馨提示

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

评论

0/150

提交评论