派生类继承方式_第1页
派生类继承方式_第2页
派生类继承方式_第3页
派生类继承方式_第4页
派生类继承方式_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

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

文档简介

1、C/C+程序设计程序设计1C/C+程序设计程序设计2四、派生类的三种继承方式四、派生类的三种继承方式 关键字关键字 private, public, protected 具有双重含义:具有双重含义: 1. 明确界定同一类层次中各成员的访问控制属性明确界定同一类层次中各成员的访问控制属性; 2.是指类上下关系中派生类对于基类成员的访问控制属是指类上下关系中派生类对于基类成员的访问控制属性的隐含演化规则。派生类的继承方式就是指第二个含义性的隐含演化规则。派生类的继承方式就是指第二个含义而言。首先抓住下面几个主要的概念:而言。首先抓住下面几个主要的概念: a. 继承不影响基类的数据成员分配继承不影响

2、基类的数据成员分配,不破坏基类的独立性不破坏基类的独立性; b. 所有的数据成员都占有内存,静态数据成员被唯一地所有的数据成员都占有内存,静态数据成员被唯一地放置在全局数据区。放置在全局数据区。C/C+程序设计程序设计3 c. 派生类对象占有的内存是基类对象占有的内存和派生派生类对象占有的内存是基类对象占有的内存和派生类新增数据成员的内存之和。类新增数据成员的内存之和。 d. 类层次本身的访问控制属性和继承方式对于对象的内类层次本身的访问控制属性和继承方式对于对象的内存分配无影响。存分配无影响。 通过继承无论是私有继承还是公共继承,派生类的对象通过继承无论是私有继承还是公共继承,派生类的对象既

3、潜在地继承上层基类的所有数据状态也潜在地拥有基类所既潜在地继承上层基类的所有数据状态也潜在地拥有基类所有的成员函数。有的成员函数。 派生类对于基类的成员访问控制属性受制于两个因素,派生类对于基类的成员访问控制属性受制于两个因素,基类本身成员的访问控制属性,派生类相对于基类的继承方基类本身成员的访问控制属性,派生类相对于基类的继承方式控制。式控制。C/C+程序设计程序设计4下面是关于编译器继承方式的描述下面是关于编译器继承方式的描述: 1). 对于任意继承方式,基类的私有成员对于派生类是对于任意继承方式,基类的私有成员对于派生类是“不可访问的不可访问的”。 2). 对于公共继承方式,基类的公共成

4、员为派生类的公对于公共继承方式,基类的公共成员为派生类的公共成员,基类的保护成员为派生类的保护成员。共成员,基类的保护成员为派生类的保护成员。 3). 对于保护继承方式,基类的公共的和保护的成员变对于保护继承方式,基类的公共的和保护的成员变为派生类的保护成员。为派生类的保护成员。 4). 对于私有继承方式,基类的公共的和保护的成员变对于私有继承方式,基类的公共的和保护的成员变为派生类的私有成员。为派生类的私有成员。 C/C+程序设计程序设计5 除开禁止派生类访问的基类的私有成员以外,无论是继除开禁止派生类访问的基类的私有成员以外,无论是继承的成员还是新增的成员,派生类的成员访问控制属性只有承的

5、成员还是新增的成员,派生类的成员访问控制属性只有三种:三种: 1). 可以在任何位置访问的公共成员。可以在任何位置访问的公共成员。 2). 可以出现在派生类中的保护成员。可以出现在派生类中的保护成员。 3). 不出现在派生类的私有成员。不出现在派生类的私有成员。 保护成员和私有成员仅由类的成员函数或者友元函数访保护成员和私有成员仅由类的成员函数或者友元函数访问,禁止派生类对象外部访问。问,禁止派生类对象外部访问。 公共成员允许对象外部访问。访问控制对于类作用域所公共成员允许对象外部访问。访问控制对于类作用域所 有的名称是同等适用的。这些名称包括成员名、类中的枚举有的名称是同等适用的。这些名称包

6、括成员名、类中的枚举常数名称和嵌套类。常数名称和嵌套类。C/C+程序设计程序设计6五、继承和不继承的语义五、继承和不继承的语义 C+语言在关于继承的特殊函数时指出:不参与继承的语言在关于继承的特殊函数时指出:不参与继承的特殊函数是构造函数、析构函数、赋值运算符函数和作为特特殊函数是构造函数、析构函数、赋值运算符函数和作为特权地位的友元函数。前已指出派生类继承了基类的数据状权地位的友元函数。前已指出派生类继承了基类的数据状态。态。 即便是私有继承,基类的私有成员依然成为派生类对象即便是私有继承,基类的私有成员依然成为派生类对象内存的一部分。内存的一部分。 友元函数不继承的含义是指:友元函数形参列

7、表的基类友元函数不继承的含义是指:友元函数形参列表的基类的对象指针只能够无禁锢的访问基类的所有成员,这种特权的对象指针只能够无禁锢的访问基类的所有成员,这种特权地位不因派生类的继承关系而使得基类的特权函数也获得对地位不因派生类的继承关系而使得基类的特权函数也获得对派生类成员的无条件访问。派生类成员的无条件访问。 C/C+程序设计程序设计7 继承的含义:基类的数据成员和函数成员在派生类可继承的含义:基类的数据成员和函数成员在派生类可访问的环境下可当作派生类的一个有机组成部分,就好像上访问的环境下可当作派生类的一个有机组成部分,就好像上下层次的区分并不存在一样。下层次的区分并不存在一样。 继承的含

8、义指形如继承的含义指形如obj.m_n 或或pobj-f()访问格式,如访问格式,如果派生类中存在相应的成员直接采用派生类的成员。果派生类中存在相应的成员直接采用派生类的成员。 如果派生类没有提供相关的成员,则使用从基类继承的如果派生类没有提供相关的成员,则使用从基类继承的可访问成员。可访问成员。 派生类成员函数的定义遵循基类的一般规则,但派生类派生类成员函数的定义遵循基类的一般规则,但派生类继承了基类的数据成员和成员函数。根据继承的方式和继承继承了基类的数据成员和成员函数。根据继承的方式和继承的语义操作相应的信息。的语义操作相应的信息。C/C+程序设计程序设计8 构造函数和析构函数不能继承表

9、现一种对象分而制之的构造函数和析构函数不能继承表现一种对象分而制之的思想,基类负责构造自身的数据成员,派生类负责构造继承思想,基类负责构造自身的数据成员,派生类负责构造继承的和新添补的数据成员,这样有利于派生类缺省构造函数自的和新添补的数据成员,这样有利于派生类缺省构造函数自动调用基类的缺省构造函数。相应的析构函数执行各自的清动调用基类的缺省构造函数。相应的析构函数执行各自的清理工作。理工作。 这种对象处理当前类数据的思想并非不适应于其它可以这种对象处理当前类数据的思想并非不适应于其它可以继承的成员函数,但由于构造和析构函数被系统自动调用的继承的成员函数,但由于构造和析构函数被系统自动调用的特

10、殊性,上下类层次之间的操作有必要加以严格的界定。特殊性,上下类层次之间的操作有必要加以严格的界定。C/C+程序设计程序设计9 基类的构造函数恰恰是可以被派生类构造函数以基类名基类的构造函数恰恰是可以被派生类构造函数以基类名显式调用的函数,不能继承的特殊函数实际上是要求重点处显式调用的函数,不能继承的特殊函数实际上是要求重点处理的函数,对于不继承的函数应该精心提交派生类的相应版理的函数,对于不继承的函数应该精心提交派生类的相应版本,以分别处理数据的变动情况。在这里不继承的含意是指本,以分别处理数据的变动情况。在这里不继承的含意是指派生类的对象自动调用的是自身类的构造函数,而不隐含地派生类的对象自

11、动调用的是自身类的构造函数,而不隐含地向上借用。向上借用。 赋值运算符函数的作用类似拷贝构造函数,不参入继承赋值运算符函数的作用类似拷贝构造函数,不参入继承机制。特别地如果类中存在指针成员,程序员应仔细处理指机制。特别地如果类中存在指针成员,程序员应仔细处理指针的动态内存资源。针的动态内存资源。 如果用户未提交构造函数和析构函数或赋值运算符函如果用户未提交构造函数和析构函数或赋值运算符函数,编译器生成相应的简单版本满足最低化的要求。数,编译器生成相应的简单版本满足最低化的要求。C/C+程序设计程序设计10 继承的含义是指基类的数据成员和函数成员在派生类可继承的含义是指基类的数据成员和函数成员在

12、派生类可访问的环境下可当作派生类的一个有机组成部分,就好像上访问的环境下可当作派生类的一个有机组成部分,就好像上下层次的区分并不存在一样。下层次的区分并不存在一样。 继承的含义指形如继承的含义指形如obj.m_n 或或pobj-f()访问格式,如访问格式,如果派生类中存在相应的成员直接采用派生类的成员。果派生类中存在相应的成员直接采用派生类的成员。 如果派生类没有提供相关的成员,则使用从基类继承的如果派生类没有提供相关的成员,则使用从基类继承的可访问成员。可访问成员。 派生类成员函数的定义遵循基类的一般规则,但派生类派生类成员函数的定义遵循基类的一般规则,但派生类继承了基类的数据成员和成员函数

13、。根据继承的方式和继承继承了基类的数据成员和成员函数。根据继承的方式和继承的语义操作相应的信息。的语义操作相应的信息。C/C+程序设计程序设计11六、派生与继承的算例六、派生与继承的算例例例 B类公共地继承类公共地继承A类类,A类的公共成员是类的公共成员是B类的公共成员类的公共成员#include class A public: long& X() return x; protected: long x; ; class B:public A public: B() x=1; ; class C:public B /* public:B:x;*/ ;void main() C b; long*

14、 p=& (b.X() +=1); printf (%dn,*p); /输出输出: 2C/C+程序设计程序设计12例例 B类保护地继承类保护地继承A类,类,A类保护的或公共的成员是类保护的或公共的成员是B类类的保护成员的保护成员#include class A protected: long x; ; class B: protected A public: long& X() return x; ;class C: protected B public: B:X; ; /C类保护地继承类保护地继承B类类void main() /public: B:X;界定成员的控制属性优于界定成员的控制属性

15、优于 /继承方式继承方式 protected 的控制属性的控制属性 C b; /public: B:X; 表示将基类中保护的成员在表示将基类中保护的成员在 /派生类中界定为派生类中界定为public属性属性 long* p=& (b.X()=1); printf (%dn,*p); /输出输出: 1C/C+程序设计程序设计13例例 B类私有地继承类私有地继承A类,类,A类的公共的或保护的成员是类的公共的或保护的成员是B类的私有成员类的私有成员#include class A private: long x; public: long& X() return x; ; class B: A pu

16、blic: long y; long& Y() return X(); ;class C: private B public: B:Y; ;void main() /public: B:Y;将基类中公将基类中公 /共的成员在派生类中界定为共的成员在派生类中界定为public属性属性 C c; long* p=& (c.Y ()=1); printf (%dn,*p); /输出输出: 1C/C+程序设计程序设计14例例 B类保护地继承类保护地继承A类,类, C类私有地继承类私有地继承B类。类。#include class A protected: long x; ; class B: prote

17、cted A public: long& operator+=(int n) return x+=n; ;class C: private B public: B:operator+=; public:B:x; ;void main() C b; b.x=1; long* p=&(b+=2); printf (%d, %dn,*p, b.x); /输出输出: 3,3C/C+程序设计程序设计15七、构造和析构的次序七、构造和析构的次序 生成派生类的对象时编译器按照如下的次序调用构造函生成派生类的对象时编译器按照如下的次序调用构造函数:数: 1. 基类构造函数。多继承情形先声明的先调用即从左到基类

18、构造函数。多继承情形先声明的先调用即从左到右的次序调用基类构造函数。右的次序调用基类构造函数。 2. 同一类层次中嵌入对象的构造函数,嵌入对象构造函同一类层次中嵌入对象的构造函数,嵌入对象构造函数按照在类中的声明次序依次调用,与成员初始化语法的排数按照在类中的声明次序依次调用,与成员初始化语法的排放次序无关。嵌入对象如果存在才调用。放次序无关。嵌入对象如果存在才调用。 3. 派生类的构造函数。确保继承树层次的构造函数全被派生类的构造函数。确保继承树层次的构造函数全被调用一次。调用一次。 C/C+程序设计程序设计16 4. 总的原则是从左到右从上到下由内向外调用构造函总的原则是从左到右从上到下由

19、内向外调用构造函数。数。 下面是构造函数成员初始化在单继承含一个嵌入对象时下面是构造函数成员初始化在单继承含一个嵌入对象时的语法格式的语法格式: CDerived:CDerived (t1 v1,t2 v2, ., tn vn ): CBase (v1,v2,v3), objEmbed (v2,v3,vn) 派生类部分子集合成员初始化;派生类部分子集合成员初始化; 冒号后的成员初始化列表中冒号后的成员初始化列表中CBase (v1,v2,v3)是对于基是对于基类构造函数的显式调用而类构造函数的显式调用而objEmbed (v2,v3,vn) 是嵌入对象是嵌入对象调用自身所隶属的构造函数。调用自

20、身所隶属的构造函数。 语法上基类名、嵌入对象名两者之间的次序可以互换。语法上基类名、嵌入对象名两者之间的次序可以互换。 C/C+程序设计程序设计17 派生类构造函数的形参作用域开始于冒号处结束于构造派生类构造函数的形参作用域开始于冒号处结束于构造函数的外层右花括号。因此冒号后构造函数中的实参可以直函数的外层右花括号。因此冒号后构造函数中的实参可以直接采用派生类的形参和其它全局变量名。接采用派生类的形参和其它全局变量名。 如下的对象定义语句:如下的对象定义语句: CDerived objd(v1, v2,.,vn ); CDerived* pObjd=new CDerived(v1,v2,.,v

21、n); 导致派生类含导致派生类含 n个形参的构造函数的调用,由此诱发一个形参的构造函数的调用,由此诱发一系列基类构造函数的启动。实参从最晚派生类层层向上传系列基类构造函数的启动。实参从最晚派生类层层向上传递,直到顶层基类构造函数中的代码首先得到执行。递,直到顶层基类构造函数中的代码首先得到执行。 为确保此种传递机制的环环相扣,派生类负责直接基类为确保此种传递机制的环环相扣,派生类负责直接基类的初始化。的初始化。C/C+程序设计程序设计18 派生类缺省的构造函数激发基类相应缺省构造函数的调派生类缺省的构造函数激发基类相应缺省构造函数的调用。成员函数可以作递归调用。用。成员函数可以作递归调用。例如

22、例如: void CDerived: Line ()Line();是递归调用,递归函数的形参是反复入栈的,隐含的是递归调用,递归函数的形参是反复入栈的,隐含的this指指针形参出现于递归函数时需要精心设计算法。针形参出现于递归函数时需要精心设计算法。 为避免递归调用发散,派生类为避免递归调用发散,派生类CDerived成员函数中显成员函数中显式地调用基类的成员函数。式地调用基类的成员函数。形式为形式为: void CDerived: Line() CBase: Line(); ;.; 对于虚掉类域分辨符的索引方式对于虚掉类域分辨符的索引方式m_n,派生类优先使用,派生类优先使用自身类新增的名称

23、。如果派生类本身未交付这个名称,则上自身类新增的名称。如果派生类本身未交付这个名称,则上溯索引可访问的基类中的名称。溯索引可访问的基类中的名称。 这是优先采用派生类成员名称的支配原则。这是优先采用派生类成员名称的支配原则。C/C+程序设计程序设计19例例 基类和嵌入对象的初始化基类和嵌入对象的初始化#include struct SData long nx; long ny; ; typedef struct tagPOINT long x; long y; POINT;class CPoint : public tagPOINT public:CPoint () CPoint (POINT initPt) x=initPt.x; y=initPt.y; ;class CBase public: CBase() CBase() delete m_p; protected: CBase (SData* pData) m_n=pDat

温馨提示

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

评论

0/150

提交评论