派生类继承方式

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
5
C/C++程序设计
Leabharlann Baidu
继承的含义:基类的数据成员和函数成员在派生类可 访问的环境下可当作派生类的一个有机组成部分,就好像上 下层次的区分并不存在一样。 继承的含义指形如obj.m_n 或pobj->f()访问格式,如 果派生类中存在相应的成员直接采用派生类的成员。 如果派生类没有提供相关的成员,则使用从基类继承的 可访问成员。
通过继承无论是私有继承还是公共继承,派生类的对象 既潜在地继承上层基类的所有数据状态也潜在地拥有基类所 有的成员函数。 派生类对于基类的成员访问控制属性受制于两个因素, 基类本身成员的访问控制属性,派生类相对于基类的继承方 式控制。
2
C/C++程序设计
下面是关于编译器继承方式的描述:
1). 对于任意继承方式,基类的私有成员对于派生类是
“ 不可访问的”。 2). 对于公共继承方式,基类的公共成员为派生类的公 共成员,基类的保护成员为派生类的保护成员。 3). 对于保护继承方式,基类的公共的和保护的成员变 为派生类的保护成员。 4). 对于私有继承方式,基类的公共的和保护的成员变 为派生类的私有成员。
3
C/C++程序设计
除开禁止派生类访问的基类的私有成员以外,无论是继 承的成员还是新增的成员,派生类的成员访问控制属性只有 三种: 1). 可以在任何位置访问的公共成员。 2). 可以出现在派生类中的保护成员。 3). 不出现在派生类的私有成员。 保护成员和私有成员仅由类的成员函数或者友元函数访 问,禁止派生类对象外部访问。 公共成员允许对象外部访问。访问控制对于类作用域所 有的名称是同等适用的。这些名称包括成员名、类中的枚举 常数名称和嵌套类。
12
C/C++程序设计
[例] B类保护地继承A类, C类私有地继承B类。
#include <stdio.h> class A { protected: long x; }; class B: protected 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, %d\n",*p, b.x); } //输出: 3,3
派生类成员函数的定义遵循基类的一般规则,但派生类 继承了基类的数据成员和成员函数。根据继承的方式和继承 的语义操作相应的信息。
6
C/C++程序设计
构造函数和析构函数不能继承表现一种对象分而制之的 思想,基类负责构造自身的数据成员,派生类负责构造继承 的和新添补的数据成员,这样有利于派生类缺省构造函数自 动调用基类的缺省构造函数。相应的析构函数执行各自的清 理工作。 这种对象处理当前类数据的思想并非不适应于其它可以 继承的成员函数,但由于构造和析构函数被系统自动调用的 特殊性,上下类层次之间的操作有必要加以严格的界定。
13
C/C++程序设计
七、构造和析构的次序
生成派生类的对象时编译器按照如下的次序调用构造函 数: 1. 基类构造函数。多继承情形先声明的先调用即从左到 右的次序调用基类构造函数。
2. 同一类层次中嵌入对象的构造函数,嵌入对象构造函 数按照在类中的声明次序依次调用,与成员初始化语法的排 放次序无关。嵌入对象如果存在才调用。 3. 派生类的构造函数。确保继承树层次的构造函数全被 调用一次。
17
C/C++程序设计
[例] 基类和嵌入对象的初始化
#include <stdio.h> 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=pData->nx; m_p=new long [m_n]; }
14
C/C++程序设计
4. 总的原则是从左到右从上到下由内向外调用构造函 数。 下面是构造函数成员初始化在单继承含一个嵌入对象时 的语法格式: CDerived::CDerived (t1 v1,t2 v2, ..., tn vn ): CBase (v1,v2,v3), objEmbed (v2,v3,vn) { 派生类部分子集合成员初始化; }
冒号后的成员初始化列表中CBase (v1,v2,v3)是对于基 类构造函数的显式调用而objEmbed (v2,v3,vn) 是嵌入对象 调用自身所隶属的构造函数。 语法上基类名、嵌入对象名两者之间的次序可以互换。
15
C/C++程序设计
派生类构造函数的形参作用域开始于冒号处结束于构造 函数的外层右花括号。因此冒号后构造函数中的实参可以直 接采用派生类的形参和其它全局变量名。 如下的对象定义语句: CDerived objd(v1, v2,...,vn ); CDerived* pObjd=new CDerived(v1,v2,...,vn); 导致派生类含 n个形参的构造函数的调用,由此诱发一 系列基类构造函数的启动。实参从最晚派生类层层向上传 递,直到顶层基类构造函数中的代码首先得到执行。 为确保此种传递机制的环环相扣,派生类负责直接基类 的初始化。
11
C/C++程序设计
[例] B类私有地继承A类,A类的公共的或保护的成员是B 类的私有成员 #include <stdio.h> class A { private: long x; public: long& X() { return x;} }; class B: A{ public: 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 ("%d\n",*p); } //输出: 1
a. 继承不影响基类的数据成员分配,不破坏基类的独立性; b. 所有的数据成员都占有内存,静态数据成员被唯一地 放置在全局数据区。
1
C/C++程序设计
c. 派生类对象占有的内存是基类对象占有的内存和派生 类新增数据成员的内存之和。 d. 类层次本身的访问控制属性和继承方式对于对象的内 存分配无影响。
16
C/C++程序设计
派生类缺省的构造函数激发基类相应缺省构造函数的调 用。成员函数可以作递归调用。例如: [void CDerived:: Line (){Line();}] 是递归调用,递归函数的形参是反复入栈的,隐含的this指 针形参出现于递归函数时需要精心设计算法。 为避免递归调用发散,派生类CDerived成员函数中显 式地调用基类的成员函数。形式为: void CDerived:: Line() { CBase:: Line(); ;...; } 对于虚掉类域分辨符的索引方式m_n,派生类优先使用 自身类新增的名称。如果派生类本身未交付这个名称,则上 溯索引可访问的基类中的名称。 这是优先采用派生类成员名称的支配原则。
9
C/C++程序设计
六、派生与继承的算例
[例] B类公共地继承A类,A类的公共成员是B类的公共成员 #include <stdio.h> 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* p=& (b.X() +=1); printf ("%d\n",*p); } //输出: 2
4
C/C++程序设计
五、继承和不继承的语义
C++语言在关于继承的特殊函数时指出:不参与继承的 特殊函数是构造函数、析构函数、赋值运算符函数和作为特 权地位的友元函数。前已指出派生类继承了基类的数据状 态。 即便是私有继承,基类的私有成员依然成为派生类对象 内存的一部分。 友元函数不继承的含义是指:友元函数形参列表的基类 的对象指针只能够无禁锢的访问基类的所有成员,这种特权 地位不因派生类的继承关系而使得基类的特权函数也获得对 派生类成员的无条件访问。
10
C/C++程序设计
[例] B类保护地继承A类,A类保护的或公共的成员是B类 的保护成员 #include <stdio.h> 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;界定成员的控制属性优于 //继承方式 protected 的控制属性 { C b; //public: B::X; 表示将基类中保护的成员在 //派生类中界定为public属性 long* p=& (b.X()=1); printf ("%d\n",*p); } //输出: 1
18
C/C++程序设计
void Line(){for (int j=0;j<m_n;j++) m_p[j]=j;} protected: long m_n; long* m_p; }; class CDerived:public CBase { public: CDerived ( SData* pData,CPoint pt); CDerived(){} ~CDerived() {delete [ ] m_p;} void Line(); void Show(); protected: CPoint m_pt; long m_n; long* m_p; }; CDerived::CDerived (SData* pData,CPoint pt) : CBase (pData),m_pt(pt)
C/C++程序设计
四、派生类的三种继承方式
关键字[ private, public, protected ]具有双重含义: 1. 明确界定同一类层次中各成员的访问控制属性; 2.是指类上下关系中派生类对于基类成员的访问控制属 性的隐含演化规则。派生类的继承方式就是指第二个含义 而言。首先抓住下面几个主要的概念:
7
C/C++程序设计
基类的构造函数恰恰是可以被派生类构造函数以基类名 显式调用的函数,不能继承的特殊函数实际上是要求重点处 理的函数,对于不继承的函数应该精心提交派生类的相应版 本,以分别处理数据的变动情况。在这里不继承的含意是指 派生类的对象自动调用的是自身类的构造函数,而不隐含地 向上借用。 赋值运算符函数的作用类似拷贝构造函数,不参入继承 机制。特别地如果类中存在指针成员,程序员应仔细处理指 针的动态内存资源。 如果用户未提交构造函数和析构函数或赋值运算符函 数,编译器生成相应的简单版本满足最低化的要求。
8
C/C++程序设计
继承的含义是指基类的数据成员和函数成员在派生类可 访问的环境下可当作派生类的一个有机组成部分,就好像上 下层次的区分并不存在一样。 继承的含义指形如obj.m_n 或pobj->f()访问格式,如 果派生类中存在相应的成员直接采用派生类的成员。 如果派生类没有提供相关的成员,则使用从基类继承的 可访问成员。 派生类成员函数的定义遵循基类的一般规则,但派生类 继承了基类的数据成员和成员函数。根据继承的方式和继承 的语义操作相应的信息。
相关文档
最新文档