C++及Windows程序设计A:第04章 继承和派生_第1页
C++及Windows程序设计A:第04章 继承和派生_第2页
C++及Windows程序设计A:第04章 继承和派生_第3页
C++及Windows程序设计A:第04章 继承和派生_第4页
C++及Windows程序设计A:第04章 继承和派生_第5页
已阅读5页,还剩89页未读 继续免费阅读

下载本文档

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

文档简介

1、继承和派生类第04章主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6 赋值兼容性4.1 基类和派生类1、什么是继承?举个简单的例子:“狗”和“黑狗”。当谈论“狗”的时候,知道它是哺乳动物,有4条腿,1条尾巴,喜欢啃肉骨头,现在谈论“黑狗”,人们会怎么说呢?一种是说“黑狗是一种哺乳动物,有4条腿,1条尾巴,喜欢吃肉骨头,并且它的毛是黑色的”。另一种是说:“黑狗就是黑毛狗”。什么是继承?比较一下黑狗的两种说法,显然后一种说法更好。那么它好在哪里呢?第一,它更简练;第二,更重要的是它反映了“狗”和“黑狗”这两个概念的内在联系。“狗”和“黑狗”之间存在一条

2、重要的联系,那就是所有的“黑狗”都是“狗”,或者说,“黑狗”是一类特殊的“狗”。根据这一条,“狗”所具有的特征,例如4条腿,1条尾巴等,“黑狗”自然都具有。也就是说,“黑狗”从“狗”那里继承了“狗”的全部特征。继承的层次结构食品水果蔬菜苹果香蕉红苹果青苹果下层具有上层的特征,同时加入自己的特征。每层比上层更具体,符合人类认识世界的规律。面向对象中的继承和派生继承和派生:一个新类可以从现有的类继承特征(属性和方法);从现有的类产生新类的过程称为派生。现有的用来派生新类的类称为基类或父类,派生出来的类称为派生类或子类。派生类可以作为基类继续派生新的类,从而形成类的层次结构。2、派生类的定义clas

3、s 派生类名 : 继承方式 基类名 private: 成员声明列表 protected: 成员声明列表 public: 成员声明列表;派生类新增的成员派生类的定义继承方式public:公有继承private:私有继承protected:保护继承通常在派生类类体中列出新增的数据成员和成员函数(个性),基类的成员将自动成为派生类的成员(共性),不用重复编写。3、派生类示例:基类class CPointint x,y;public:CPoint() x=0; y=0; CPoint(int a,int b) x=a; y=b; void SetVal(int a, int b)x=a; y=b;in

4、t GetX() return x; int GetY() return y; ;派生类示例:派生类class Circle : public CPointint radius;public:Circle() radius=0; Circle(int a,int b,int r):CPoint(a,b) radius=r; void SetR(int r) radius=r; int GetR() return radius; ;初始化从基类继承得来的成员派生类示例:mainvoid main()Circle c(3,4,5);coutc.GetX()endl;coutc.GetY()endl

5、;coutc.GetR()endl;运行结果345派生类示例说明派生类构造函数必须提供初始化从基类继承来的数据成员的机制Circle:Circle(int a,int b,int r):CPoint(a,b) radius=r; 公有派生类对象,可以访问基类的公有成员,就像访问本类的公有成员函数一样。对于私有成员,需要借助公有成员函数间接访问。4、派生类对基类的扩充派生类继承了基类除构造函数、析构函数以外所有的数据成员和成员函数,实现了代码重用。派生类必然具有某些和基类不同的属性和行为,需要对基类进行扩充和改造。扩充:在派生类中增加成员函数和数据成员。改造:当继承而来的成员不能满足需要时,可以

6、进行重载或覆盖。重载即在同一个类中定义同名函数但参数不同;覆盖是定义与基类同名的函数。派生类对象class Circle : public CPointint radius;public:;Circle c(3,4,5);c3xy45radius主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6 赋值兼容性4.1 基类和派生类1、继承方式继承方式决定了基类成员在派生类中的访问属性。派生类中新增成员函数基类成员派生类对象基类成员三种访问方式共有继承:public保护继承:protected私有继承:private2、公有继承:public基类的公有成员

7、在派生类中仍然是公有成员;派生类中可以访问;通过派生类对象可以访问。基类的保护成员在派生类中仍然是保护成员;派生类中可以访问;通过派生类对象不可以访问。基类的私有的成员在派生类中不可访问,即在派生类成员函数中,不能访问从基类继承过来的私有成员,虽然它们存在于内存中;通过派生类对象更不能访问。公有继承:public示例class CPointint x; /私有成员protected:int y; /保护成员public:CPoint(int a,int b) x=a; y=b; void SetX(int a) x=a;int GetX() return x; ;不能访问基类私有成员!clas

8、s Circle : public CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) x=a; y=b; radius=r; ;X不可访问基类私有成员,但能访问保护成员解决办法:调用基类公有接口class Circle : public CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) SetX(a

9、); y=b; radius=r; ;通过基类的公有成员函数间接访问小结:公有继承访问权限基类A公有成员私有成员保护成员基类A对象基类A的成员函数小结:公有继承访问权限基类A公有成员私有成员保护成员基类A对象基类A的成员函数公有派生类B公有成员私有成员保护成员派生类B对象派生类B的成员函数3、私有继承:private基类的私有成员在派生类中是不可访问的,而公有和保护成员成为派生类的私有成员。通过派生类的对象不能访问基类的任何成员,需要在派生类中定义公有接口。通过私有继承,基类中的所有成员变成派生类的私有成员,将该派生类作为基类再继续派生时,这时即使使用公有派生,原基类公有成员在新的派生类中也将

10、是不可访问的。私有继承:private示例class CPointint x; /私有成员protected:int y; /保护成员public:CPoint(int a,int b) x=a; y=b; void SetX(int a) x=a;int GetX() return x; ;基类私有成员不能访问class Circle : private CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) x=a; y=b; radius=r;

11、;X不可访问基类私有成员,但能访问保护成员解决办法:调用基类公有接口class Circle : private CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) SetX(a); y=b; radius=r; ;通过基类的公有成员函数间接访问二级继承:全部不能访问class Test : public Circleint color;public:Test(int a,int b,int r,int c) : Circle(a,b,r) col

12、or=c; void SetAll(int a,int b,int r,int c) SetX(a); y=b; radius=r; ;它们都相当于Circle的私有成员,不可访问X解决办法:公有接口接力class Test : public Circleint color;public:Test(int a,int b,int r,int c) : Circle(a,b,r) color=c; void SetAll(int a,int b,int r,int c) Set(a,b,r); radius=r; ;可以调用Circle中的公有成员Set小结:私有继承访问权限基类A公有成员私有成

13、员保护成员基类A对象基类A的成员函数私有派生类B公有成员私有成员保护成员派生类B对象派生类B的成员函数小结:私有继承访问权限私有成员保护成员公有成员基类A对象基类A的成员函数私有成员保护成员公有成员私有继承派生类B对象派生类B的成员函数私有成员保护成员公有成员公有继承派生类C对象派生类C的成员函数4、保护继承:protected基类的私有成员在派生类中是不可访问的,而公有和保护成员成为派生类的保护成员。通过派生类的对象不能访问基类的任何成员,需要在派生类中定义公有接口。通过保护继承,基类中的保护和公有成员变成派生类的保护成员,将该派生类作为基类再继续派生时,只要不使用私有继承,它们在派生类中可

14、以继续访问。保护继承:protected示例class CPointint x; /私有成员protected:int y; /保护成员public:CPoint(int a,int b) x=a; y=b; void SetX(int a) x=a;int GetX() return x; ;基类私有成员不能访问class Circle : protected CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) x=a; y=b; radius=

15、r; ;X不可访问基类私有成员,但能访问保护成员解决办法:调用基类公有接口class Circle : protected CPointint radius;public:Circle(int a,int b,int r):CPoint(a,b) radius=r; void Set(int a,int b,int r) SetX(a); y=b; radius=r; ;通过基类的公有成员函数间接访问多次继承,保护属性不变class Test : public Circleint color;public:Test(int a,int b,int r,int c) : Circle(a,b,r

16、) color=c; void SetAll(int a,int b,int r,int c) SetX(a); y=b; radius=r; ;它们都相当于Circle的保护成员,可以访问小结:保护继承访问权限基类A公有成员私有成员保护成员基类A对象基类A的成员函数保护派生类B公有成员私有成员保护成员派生类B对象派生类B的成员函数小结:保护继承访问权限私有成员保护成员公有成员基类A对象基类A的成员函数私有成员保护成员公有成员保护继承派生类B对象派生类B的成员函数私有成员保护成员公有成员公有继承派生类C对象派生类C的成员函数私有成员保护成员公有成员私有成员保护成员公有成员公有继承私有成员保护成

17、员公有成员公有继承5、对象访问基类私有成员基类A对象派生类B对象派生类C对象私有成员保护成员公有成员私有成员保护成员公有成员私有继承私有成员保护成员公有成员私有继承对象访问基类私有成员基类A对象派生类B对象派生类C对象主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6 赋值兼容性4.1 基类和派生类1、构造基类成员由于派生类继承了基类的所有成员,派生类的每一个对象都包含基类数据成员的值,在派生类构造函数中应该提供初始化基类数据成员的机制。与容器类初始化对象成员类似,派生类也必须通过初始化列表初始化基类数据成员。对本类的数据成员,可以用初始化列表,也可

18、以放在构造函数体内赋值。构造函数调用顺序创建派生类对象时AB(A派生B)。调用A中对象成员(如果有)对应的构造函数先调用基类A构造函数调用B中对象成员(如果有)对应的构造函数调用派生类B的构造函数ABC(A派生B,B再派生C)先调用基类A的构造函数调用直接派生类B的构造函数调用间接派生类C的构造函数析构函数的调用顺序创建派生类对象时AB(A派生B)。调用派生类B的析构函数调用B中对象成员(如果有)对应的析构函数先调用基类A析构函数调用A中对象成员(如果有)对应的析构函数ABC(A派生B,B再派生C)调用间接派生类C的析构函数调用直接派生类B的析构函数先调用基类A的析构函数2、构造函数的调用顺序

19、示例class CPointint x,y;public:CPoint() x=0; y=0; CPoint(int a,int b) x=a; y=b; void Set(int a, int b)x=a; y=b;void Show() couta“,”bendl; ;构造函数的调用顺序示例class Circle : public CPointint radius;CPoint p;public:Circle(int a,int b,int aa,int bb,int r);void Set(int a,int b,int r) CPoint:Set(a,b); radius=r; vo

20、id Show() coutradius“,”; CPoint:Show();析构函数的调用顺序Circle:Circle(int a,int b,int aa,int bb,int r):CPoint(a,b),p(aa,bb)radius=r;Circle c(3,4,5,6,8);调用顺序:基类p本类构造函数说明在继承过程中,构造函数和析构函数不能被继承。在创建派生类对象时,按顺序由系统自动调用基类和派生类的构造函数,而不能在派生类中显式调用基类构造函数。不能在派生类中显式调用基类的析构函数。主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6

21、赋值兼容性4.1 基类和派生类1、多继承的概念C+允许使用多个基类进行继承,称为多继承。派生类继承所有基类的成员。定义多继承派生类语法与单继承语法类似,但要指定所有要继承的基类以及每个基类的继承方式。class 派生类名称: 继承方式1 基类名1,继承方式2 基类2, 增加的成员;2、多继承示例:基类const double PI=3.1415926;class Circledouble radius;public:Circle(double r=0) radius=r; double area() return PI*radius*radius; ;多继承示例:基类class Tabledo

22、uble height;public:Table(double h=0) height=h; double GetHeight() return height; ;多继承示例:派生类class RoundTable:public Table,public Circleint color;public:RoundTable(double h,double r,int c) : Table(h),Circle(r),color(c) int GetColor() return color; ;多继承示例:mainvoid main()RoundTable table(10,3,2);couthei

23、ght: table.GetHeight()endl;coutarea: table.area()endl;coutcolor: table.GetColor()endl;运行结果height: 10area: 28.2743color: 2多继承说明在多继承派生类的构造函数中,要通过初始化列表的形式调用直接基类的构造函数。构造函数的执行顺序:先执行基类构造函数,再执行派生类构造函数;多个基类构造函数按照定义派生类时的顺序,与初始化列表中的顺序无关。使用多继承容易造成混乱,应避免使用。3、多继承的二义性class Base1public:void draw() ;class Base2publ

24、ic:void draw() ;多继承的二义性class Derived: public Base1, public Base2 ;void main()Derived d;d.draw();无法确定调用哪个draw()?二义性解决方法:限定前缀class Derived: public Base1, public Base2 ;void main()Derived d;d.Base1:draw();d.Base2:draw();限定前缀,但不好!二义性解决方法:覆盖技术class Derived: public Base1, public Base2public:void draw() if

25、() Base1:draw();else Base2:draw(); ;void main()Derived d;d. draw();派生类中提供接口,方便用户4、另一种二义性当一个派生类从几个基类继承而来,这几个基类又是同一个基类的直接派生类,这样继承而来的派生类同样会出现二义性问题。AABCDD继承了两份A的成员多继承的二义性class Apublic:int a;class B : public A ;class C : public A ;class D : public B, public C public: int GetValue() return a; 无法确定是从B继承的a,

26、还是从C继承的a引用谁的成员?class D : public B, public C public: void GetValue() return A:a; void main()D d;coutd.GetValue();Xvoid GetValue() return B:a; 勉为其难?void main()D d; d.SetValue();dA:aA:aB类其它成员C类其它成员类其它成员从B类继承从C类继承两份数据void D: SetValue() B:a=5; 易造成一致性问题?主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6 赋值兼容

27、性4.1 基类和派生类1、二义性解决之道:虚基类将总的基类定义成虚基类,可以确保该基类通过多条路径继承时,派生类仅仅继承该基类次,避免由于多路径继承造成的二义性。class A public:int a;class B : virtual public A ;class C : virtual public A ;A是B和C的虚基类二义性解决之道:虚基类class D : public B, public Cpublic:void SetValue() a=5; ;ABCD虚基类确保A的成员只有1份二义性解决之道:虚基类void main()D d; d.SetValue();从B类继承从C类

28、继承void D: SetValue() a=5; / B:a=5 / A:a=5 d指针指针B类其它成员C类其它成员D类其它成员A:aA的成员仅此1份完全等效虚基类的要点C+规定,由虚基类沿不同路径进行继承时,要求最终的派生类在构造函数中通过初始化参数列表对虚基类成员直接进行初始化,而中间层次的类对虚基类成员的初始化被忽略,尽管它们提供了初始化列表;确保虚基类构造函数只被调用一次。进行多继承时,同时有虚基类和非虚基类,则虚基类构造函数优先执行。2、虚基类完整示例:虚基类class Apublic:int a;A(int n) a=n; ;虚基类完整示例:中间派生类class B : virt

29、ual public Apublic:int b;B(int a, int n) : A(a) b=n; ;class C : virtual public Apublic:int c;C(int a,int n) : A(a) c=n; ;虚基类完整示例:最终派生类class D : public B, public Cpublic:int d;D(int a,int b,int c,int n) :B(n,b), C(n,c), A(a) d=n; void main()D obj(1,2,3,4);被忽略初始化b和c直接初始化基类补充说明定义D类对象时,由D类构造函数直接初始化虚基类成员

30、,而忽略B类和C类的对基类的初始化调用;如果要定义B(或C类)的对象,则B类构造函数中对A类的构造函数调用会起作用。使用多继承,可以实现比较复杂的继承和共享逻辑,但容易造成二义性等问题,往往需要使用虚基类,但虚基类的使用非常容易出错,应该慎用。主要内容4.2 继承方式4.3 派生类的构造函数和析构函数4.4 多重继承4.5 虚基类4.6 赋值兼容性4.1 基类和派生类1、赋值兼容性概念如果类B公有继承于类A,类B的每一个对象也是一个类A的对象,但反之则不然。“每一只黑狗都是狗”。如果说A表示一个比B更普遍的概念,也就是B表示一个比A更特殊的概念。可以断言: 在可以使用类A的对象的任何地方,则类

31、B的对象同样也能使用,因为每一个类B的对象“就是一个”类A的对象。另一方面,如果需要一个类B的对象,则类A的对象就不行;每个B都是A,但反之则不然。每个学生都是人class Person .;class Student: Public Person .;每个学生都是人,但并不是每个人都是学生。可以期望任何一件对于人来说是真实的事情,对学生也是真实的,例如他或她都有生日,对于学生同样也是真实的。但却不能期望每一件对于学生来说是真实的事情,对所有的人都是真实的。 “人”的概念要比“学生”的概念来得更广泛些;而“学生”则是一种特殊类型的“人”。2、赋值兼容性规则每一个派生类的对象,都是基类的一个对象

32、。赋值兼容规则是指在公有派生情况下,一个公有派生类的对象可以当作基类的对象使用,反之则禁止。派生类的对象可以赋值给基类对象。派生类的对象可以初始化基类的引用。指向基类的指针也可以指向派生类。通过基类对象名、指针只能使用从基类继承的成员3、赋值兼容性示例:CPoint类class CPointint x,y;public:CPoint() x=0; y=0; CPoint(int a,int b) x=a; y=b; void Set(int a, int b)x=a; y=b;void Show() coutx“,”yendl; ;Circle类class Circle : public CPointint radius;public:Circle(int a,int b,int r) : CPoint(a,b) radius=r; void Set(int a,int b,int r) radius=r; void Show() coutradiusShow(); /调用基类的Showb=a;b.Show();运行结果2,32,32,3调用

温馨提示

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

评论

0/150

提交评论