继承性和派生类.ppt
《继承性和派生类.ppt》由会员分享,可在线阅读,更多相关《继承性和派生类.ppt(113页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第七章 继承性和派生类,7.1 基类和派生类,7.2 单继承,7.3 多继承,7.4 虚基类,7.1 基类和派生类,继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。派生类不是简单地继承基础类的特性,它可以调整部分成员的特性,也可以增加一些新成员。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。 多态性(polymorphism)也是面向对象程序设计的标志性特征。多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载
2、,属于多态性中的编译时的多态性。本章讲解的以虚基类为基础的多态性是运行时的多态性。体现了类推和比喻的思想方法。,7.1 基类和派生类,1、基类与派生类,基类(父类):已存在的用来派生新类的类;,派生类(子类):由已存在的类派生出的新类;,2、单继承与多继承,单继承:从一个基类派生的继承;,多继承:从多个基类派生的继承;,7.1 基类和派生类,(a)多重继承,(b)单继承,一个基类可以直接派生出多个派生类,派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个层次结构。,7.1.1 派生类的定义,单继承的定义格式为: class 派生类名 :继承方式 基类名 派生类新定义成员 ;,
3、public:公有派生 private:私有派生 protected:保护派生,规定基类成员在派生类中的访问权限,多继承的定义格式为: class 派生类名 :继承方式1 基类名1, 继承方式2 基类名2, 派生类新定义成员 ;,单继承的定义格式:,class B /定义基类B private: int x; protected: int y; public: int z; . ;,class A:public B /由类B派生出类A private: int a; protected: int b; public: int c; . A a; /定义类A的一个对象a,7.1.1 派生类的定义
4、,不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收,声明一个和某基类成员同名的新成员派生类中的新成员就屏蔽了基类同名成员称为同名覆盖,派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。,7.1.2 派生类的三种继承方式:,公有继承(public),保护继承(private),私有继承(protected),公有继承:,公有继承其特点是: 基类的公有成员和保护成员作为派生类的成员时,都保持原有状态,而私有成员仍是私有。,公有继承:,特 别 提 示,公有继承时,派生类的对象只可访问基类中的公有成员,不能访问其它成员。派生类的成员函数可以访问基类中的公有成员和保护成员
5、,不可访问其私有成员。,公有继承:,class B private: int x; protected: int y; public: int z; .; class A:public B private: int a; protected: int b; public: int c; . A a;,说明: 类B是基类,类A是从类B公有派生的,因此类B中的public、protected属性的成员可继承到类A中来,且保持原来的属性。 因此,类A中有5个数据成员:a,b,c,y(protected属性),z(public属性)。,对象a可以直接访问public成员z和c,不能访问a,b,y。,注
6、意:,在不考虑派生类时,类中的private和protected属性的成员没有什么不同,它们都可以被类的成员函数访问,而都不能被该类的对象直接访问。 其差异主要是在派生类中,当公有继承时,基类中protected属性的成员可以作为派生类的protected属性的成员,而private属性的成员不能作为派生类的成员,class student private: int age; protected: char sex; public: int Getage( ); ; class graduatestudent: public student private: int stunum; publi
7、c: int Getnum( ); ; void graduatestudent:Getnum( )/派生类成员函数定义 /cout”age:”ageendl; /不可访问基类的私有成员 cout”stunum:”stunumendl; /派生类的私有成员 cout”age:”Getage( )endl; /基类的公有成员 cout“sex:”sexendl; /即:student:sex 基类的保护成员 ,保护继承:,其特点是:基类的所有公有成员和保护成员都作为派生类的保护成员,基类的私有成员仍是私有的。 即基类的公有成员和保护成员都作为派生类的保护成员。派生类的其他成员可以直接访问它们。派
8、生类的对象不可以直接访问它们。,.,class B private: int x; protected: int y; public: int z; .; class A:protected B private: int a; protected: int b; public: int c; . A a;,说明: 类B是基类,类A是从类B保护派生的,因此类B中的public、protected属性的成员可继承到类A中来,均变为protected属性。 因此,类A中有5个数据成员:a,b,c,y(protected属性),z(protected属性)。,对象a可以直接访问public成员c,不能
9、访问a,b,y,z。,私有继承:,基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。,特 别 提 示,.,class B private: int x; protected: int y; public: int z; .; class A:private B private: int a; protected: int b; public: int c; . A a;,说明: 类B是基类,类A是从类B私有派生的,因此类B中的public、protected属性的成员可继承到类A中来,均变为private属性。 因此,类A中有5个数据成员:a,b,c,y(pri
10、vate属性),z( private属性)。,对象a可以直接访问public成员c,不能访问a,b,y,z。,公有派生和私有派生的访问权限,#include class A public: void f1(); protected: int j1; private: int i1; ; class B:public A public: void f2(); protected: int j2; private: int i2; ;,class C:public B public: void f3(); ; 1、派生类B中成员函数f2()能否访问基类A中的成员:f1()、j1和i1? 2、派生类
11、B的对象b1能否访问基类A中的成员:f1()、j1和i1? 3、派生类C中的成员函数f3()能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1? 4、派生类C的对象c1能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1?,1、派生类B中成员函数f2()能否访问基类A中的成员:f1()、j1和i1?,可以访问f1()和j1,不可以访问i1; 原因:类B对类A是直接继承,可以访问A中的公有成员和保护成员,而不可以访问私有成员;,2、派生类B的对象b1能否访问基类A中的成员:f1()、j1和i1?,可
12、以访问f1(),不可以访问j1和i1; 原因:类B的对象b1对类A中的成员是水平访问,可以访问A中的公有成员,而不可以访问保护成员和私有成员;,4、派生类C的对象c1能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1?,可以访问直接基类中的f2()和j2以及间接基类中的f1() 和j1,不可以访问i2和i1; 原因:类C对类B是直接继承,原因同1;类C对类A是垂直 访问,可以访问A中的公有成员和保护成员,而不可以访 问私有成员;,可以访问直接基类中的f2()以及间接基类中的f1(),其 他都不可以访问; 原因:类C的对象c1对B中的成员是水平访
13、问,原因同2; c1对A的访问,相当于先直接继承后水平访问;,3、派生类C中的成员函数f3()能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员: f1()、j1和i1?,#include class A public: void f(int i) coutiendl; void g() coutgendl; ; class B:A public: void h() couthendl; A:f; ; void main() B d1; d1.f(6); d1.g(); d1.h(); ,缺省继承方式 为private,将基类中的成员 说明为派生类中 的成员,编译错。
14、B以私有继承方式继承A, 因此B的对象b1不能访问A的成员函数,输出(2): 6 h,输出(5): 6 g h,问题:,1、执行该程序时,哪个语句会出现编译错?,2、去掉出错语句后,执行结果是什么?,3、类B从类A继承时的缺省继承方式是什么?,4、派生类B中,A:f的含义是什么?,5、将B的继承方式改为public,输出结果是什么?,7.2 单继承,在单继承中,每个类可以生成多个派生类,但是每个派生类只能有一个基类。 派生类中只有一个基类是单继承的主要特点。,7.2.1 派生类构造函数和析构函数,1.派生类的构造函数,构造函数不能被继承;,派生类构造函数的工作:,对自己的数据成员进行初始化;,
15、负责调用基类构造函数使基类的数据成员得以初始化;,调用子对象的构造函数,对派生类中的子对象进行初始化;,必须在成员 初始化列表 中进行,派生类构造函数格式:,() :(), () ,成员初始化列表,成员初始化列表,B(int i,int j,int k):a(i,j)b=k;,子对象a,对子对象成员函数的调用,输出: 6,7 8,#include class A public: A(int i); void print(); const int ,A:A(int i ) a=i,r=a; /不能这样哟!,结果为:100:10:100 0:10:0,派生类构造函数的调用顺序如下:,基类的构造函数
16、 子对象类的构造函数(若有) 派生类构造函数,注意:,1、若基类中未定义构造函数,则派生类构造函数的定义中可以省略对基类构造函数的调用。 2、若基类的构造函数使用了参数,则派生类必须定义构造函数,为基类构造函数提供参数。,#include class A public: A() a=0;coutAs default constructor called.n; A(int i) a=i;coutAs constructor called.n; A() coutAs destructor called.n; void print() const couta,; int Geta()return a
17、; private:int a; class B:public A public: B() b=0;coutBs default constructor called.n; B(int i,int j,int k);,B()coutBs destructor called.n; void print(); private:int b;A aa; B:B(int i,int j,intk):A(i),aa(j) b=k; coutBs constructor called.n; void B:print() A:print(); coutb,aa.Geta()endl; void main()
18、B bb2; bb0=B(1,2,5); bb1=B(3,4,7); for(int i=0;i2;i+) bbi.print();,#include class data int x; public: data(int x)data:x=x; coutclass datan; ; class A public: A(int x):d1(x) coutclass An; private: data d1; ;,class B:public A data d2; public: B(int x) : A(x),d2(x) coutclass Bn; ; class C:public B publ
19、ic: C(int x) : B(x) coutclass Cn; ; void main( ) C object(5); ,class data class A class data class B class C,派生类析构函数:,执行派生类的析构函数时,基类的析构函数也将被调用;,析构函数不能被继承;,析构函数的执行顺序与构造函数严格相反;,派生类的析构函数;,基类的析构函数;,#include class M public: M()m1=m2=0; M(int i,int j); M(); void Print(); private: int m1,m2; M:M(int i,int
20、j) m1=i,m2=j; coutMs constructor called. m1, m2endl; M:M() coutMs destructor called. m1, m2endl; void M:Print() coutm1, m2, ;,class N:public M public: N() n=0; N(int i,int j,int k); N(); void Print(); private: int n; N:N(int i,int j,int k):M(i,j),n(k) coutNs costructor called. nendl; N:N() coutNs de
21、structor called. nendl; void N:Print() M:Print(); coutnendl; void main() N n1(5,6,7), n2(-2,-3,-4); n1.Print();n2.Print();,运行结果:,3.派生类构造函数使用中应注意的问题,派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数;,当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径;,编译器自动生成缺省构造函数,设基类数据成员为m个,派生类数据成员为n个, 派生类的参
22、数个数为x,则:0=x=m+n;,#include class A public: A() a=0; A(int i) a=i; void Print() couta, ; private: int a; class B:public A public: B() b1=b2=0; B(int i) b1=i;b2=0; B(int i,int j,int k):A(i),b1(j),b2(k) void Print() A:Print(); coutb1, b2endl; private: int b1,b2; void main() B d1,d2(5),d3(4,5,6); d1.Prin
23、t(); d2.Print(); d3.Print();,输出: 0,0,0 0,5,0 4,5,6,7.2.2 子类型和赋值兼容规则,1、子类型 有一个特定的类型S,当且仅当它至少提供了类型T的行为,则称类型S是类型T的子类型。 子类型是类型间的一般和特殊的关系。 在继承中,公有继承可以实现子类型。 如:class A public: void print() const cout“ok!”; class B:public A public: void f() cout“No!”; ; void f1(const A 结果为:ok!,对类A的对象操作的函数,也就可对类A的子类(类B)的对象进
24、行操作,2.类型适应,指两种类型之间的关系。如:派生类适应于基类。即派生类的对象可以用于基类对象所能使用的场合。 子类型化与类型适应是一致的。 子类型的重要性是能减轻编程负担。一个函数可以用于某类型的对象,也就可用于该类型的各个子类型的对象,不必进行函数重载。,3.赋值兼容规则,赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。 赋值兼容规则替代的几种情况: 派生类的对象可以赋值给基类对象。 派生类的对象可以初始化基类的引用。 派生类的对象的地址可以赋给指向基类的指针。,例题1 下列对派生类的描
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 继承 以及 派生
限制150内