继承与派生类课件_第1页
继承与派生类课件_第2页
继承与派生类课件_第3页
继承与派生类课件_第4页
继承与派生类课件_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

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

文档简介

第七章继承机制

基类和派生类

单继承

多继承

虚基类

应用实例

第七章继承机制 基类和派生类 继承是面向对象程序设计的基本特征之一,是从已有的类基础上建立新类。继承性是面向对象程序设计支持代码重用的重要机制。面向对象程序设计的继承机制提供了无限重复利用程序资源的一种途径。通过C++语言中的继承机制,一个新类既可以共享另一个类的操作和数据,也可以在新类中定义已有类中没有的成员,这样就能大大的节省程序开发的时间和资源。

继承是面向对象程序设计的基本特征之一,是从已有的类基础上

基类和派生类

继承是类之间定义的一种重要关系。定义类B时,自动得到类A的操作和数据属性,使得程序员只需定义类A中所没有的新成分就可完成在类B的定义,这样称类B继承了类A,类A派生了类B,A是基类(父类),B是派生类(子类)。这种机制称为继承。 称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。派生类可以具有基类的特性,共享基类的成员函数,使用基类的数据成员,还可以定义自己的新特性,定义自己的数据成员和成员函数。 在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。图7-1反映了类之间继承和派生关系。

基类和派生类 继承是类之间定义的一种重要关系。定义类B1,B2的派生类(多继承)AB1B2C1C2C3A的派生类(单继承)C3的基类B1,B2的基类A的派生类C1,C2,C3的基类B1的派生类图7-1类之间的继承与派生关系B1,B2的派生类(多继承)AB1B2C1C2C3A的派生类

派生类的定义格式 单继承的定义格式如下:class<派生类名>:<继承方式><基类名>{public://派生类新定义成员members;<private:>members;<protected:>members;};派生类的定义格式 其中,<派生类名>是新定义的一个类的名字,它是从<基类名>中派生的,并且按指定的<继承方式>派生的。<继承方式>常作用如下三种关键字给予表示: public:表示公有继承; private:表示私有继承,可默认声明; protected:表示保护继承。 其中,<派生类名>是新定义的一个类的名字,它是从<基类名 多继承的定义格式如下:class<派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{public://派生类新定义成员members;<private:>members;<protected:>members; }; 多继承的定义格式如下:

派生类的三种继承方式 在介绍公有继承(public)、私有继承(private)和保护继承(protected)的继承方式前,先看一个例子。

派生类的三种继承方式#include<iostream.h>classOne{public:One(void){cout<<"ConstructorforOne\n";one=1;};intone;};classTwo{public:Two(void){cout<<"ConstructorforTwo\n";two=2;};inttwo;};#include<iostream.h>classTwoclassThree{public:Three(void){cout<<"ConstructorforThree\n";three=3;};intthree;};classDerived:privateOne,privateThree,publicTwo{public:Derived(void):One(),Two(),Three(){cout<<"Derivedconstructorcalled\n";};voidshow_value(void){cout<<one<<two<<three<<endl;};};voidmain(void){Derivedmy_class;my_class.show_value();cout<<my_class.two;}classThreeclassDerived:pri参考上述实例,说明公有继承(public)、私有继承(private)和保护继承(protected)是常用的三种继承方式:参考上述实例,说明公有继承(public)、私有继承(pri1.公有继承(public)。 公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员仍然是私有的。2.私有继承(private)。 私有继承的特点是基类的公有成员和保护成员作为派生类的私有成员,并且不能被这个派生类的子类访问。3.保护继承(protected)。 保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。1.公有继承(public)。继承方式基类特性派生类特性公有继承publicpublicprotectedprotectedprivate不可访问私有继承publicprivateprotectedprivateprivate 不可访问保护继承publicprotectedprotectedprotectedprivate不可访问 表7-1不同继承方式的基类和派生类特性

继承方式基类特性派生类特性公有继承publicpublicp (1)在公有继承时,派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。这里,一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。

(2)在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。

(3)对于保护继承方式,这种继承方式与私有继承方式的情况相同。两者的区别仅在于对派生类的成员而言,对基类成员有不同的可访问性。

(4)对于基类中的私有成员,只能被基类中的成员函数和友元函数所访问,不能被其他的函数访问。

(1)在公有继承时,派生类的对象可以访问基类中的公有成员

访问控制 类通过派生定义,形成类的等级,派生类中用“类名

::成员”访问基类成员。在建立一个类等级后,通常创建某个派生类的对象来使用这个类等级,包括隐含使用基类的数据和函数。 派生类对基类成员可以有不同的访问方式: 派生类可以覆盖基类成员 派生类不能访问基类私有成员 基类的公有段和保护段成员访问权对派生类保持不变(公有继承) 基类的公有段和保护段成员成为派生类的私有成员(私有继承) 具体说明如下:

访问控制1.定义与派生类同名的成员

如果派生类定义了与基类同名的成员,称派生类的成员覆盖了基类的同名成员,若要在派生类中使用基类同名成员,可以显式地使用类名限定符: 类名::成员 2.派生类不能访问基类私有成员 3.公有继承 派生类对基类的公有继承使用关键字public描述。1.定义与派生类同名的成员 4.私有继承和保护继承 私有继承:派生类对基类的公有继承使用关键字private描述(可缺省),基类的所有公有段和保护段成员都成为派生类的私有成员。 保护继承:派生类对基类的公有继承使用关键字protected描述,基类的所有公有段和保护段成员都成为派生类的保护成员,保护继承在程序中很少应用。5.派生类中的静态成员 不管公有派生类还是私有派生类,都不影响派生类对基类的静态成员的访问,派生类对基类静态成员必须显式使用以下形式:

类名::成员

4.私有继承和保护继承6.访问声明 C++提供一种调节机制,称为访问声明,使得X的某些成员能被类Z所访问。 注意: (1)访问声明仅仅调整名字的访问权限,不可说明为任何类型 (2)访问声明不允许在派生类中降低或提升基类成员的可访问性 (3)对重载函数名的访问声明将调整基类所有同名函数的访问域6.访问声明例子:P195——简单图形程序设计例子:

基类与派生类的关系 任何一个类都可以派生出一个新类,派生类也可以再派生出新类,因此,基类和派生类是相对而言的。一个基类可以是另一个基类的派生类,这样便形成了复杂的继承结构,出现了类的层次。一个基类派生出一个派生类,它又做另一个派生类的基类,则原来的基类为该派生类的间接基类。

1.派生类是基类的具体化。 2.派生类是基类定义的延续。 3.派生类是基类的组合。 派生类将其本身与基类区别开来的方法是添加数据成员和成员函数。因此,继承的机制将使得在创建新类时,只需说明新类与已有类的区别,从而大量原有的程序代码都可以复用。基类与派生类的关系

单继承 单继承是指派生类有且只有一个基类的情况,在单继承中,每个类可以有多个派生类,但是每个派生类只能有一个基类,从而形成树形结构。

构造函数 构造函数不能够被继承,C++提供一种机制,使得在创建派生类对象时,能够调用基类的构造函数来初始化基类数据 也就是说,派生类的构造函数必须通过调用基类的构造函数来初始化基类子对象。所以,在定义派生类的构造函数时除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数使基类的数据成员得以初始化。

单继承 单继承是指派生类有且只有一个基类的情况,在单 派生类构造函数的一般格式如下:<派生类名>(<派生类构造函数总参数表>):<基类构造函数>(<参数表1>),<子对象名>(<参数表2>){<派生类中数据成员初始化>}; 派生类构造函数的调用顺序如下: (1)调用基类的构造函数,调用顺序按照它们继承时说明的顺序。 (2)调用子对象类的构造函数,调用顺序按照它们在类中说明的顺序。 (3)派生类构造函数体中的内容。 派生类构造函数的一般格式如下:

析构函数 由于析构函数也不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数时的顺序正好相反。

继承中构造函数的调用顺序 如果派生类和基类都有构造函数,在定义一派生类时,系统首先调用基类的构造函数,然后再调用派生类的构造函数。在继承关系下有多个基类时,基类构造函数的调用顺序取决于定义派生类时基类的定义顺序。

析构函数

应注意的问题 在实际应用中,使用派生类构造函数时应注意如下几个问题: (1)派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有默认的构造函数或者根本没有定义构造函数。当然,基类中没有定义构造函数,派生类根本不必负责调用基类构造函数。

(2)当基类的构造函数使用一个或多个参数时,则派生类必须定义构造函数,提供将参数传递给基类构造函数途径。在有的情况下,派生类构造函数体可能为空,仅起到参数传递作用。

应注意的问题

多继承

多继承的概念 可以为一个派生类指定多个基类,这样的继承结构称为多继承。多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个继承。 多继承下派生类的定义格式如下:class<派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{<派生类类体>}; 其中,<继承方式1>、<继承方式2>、…是三种继承方式:public,private和protected之一。

多继承多继承的概念

多继承的构造函数 在多继承的情况下,多个基类构造函数的调用次序是按基类在被继承时所声明的次序从左到右依次调用,与它们在派生类的构造函数实现中的初始化列表出现的次序无关。 派生类的构造函数格式如下:<派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>),…<子对象名>(<参数表n+1>),…{<派生类构造函数体>} 其中,<总参数表>中各个参数包含了其后的各个分参数表。多继承的构造函数 派生类构造函数执行顺序是先执行所有基类的构造函数,再执行派生类本身构造函数。处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。 多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。

派生类构造函数执行顺序是先执行所有基类的构造函数,再执行

二义性和支配原则 一般说来,在派生类中对基类成员的访问应该是惟一的。但是,由于多继承情况下,可能造成对基类中某个成员的访问出现了不惟一的情况,则称为对基类成员访问的二义性问题。 1.同名成员的二义性 在多重继承中,如果不同基类中有同名的函数,则在派生类中就有同名的成员,这种成员会造成二义性。二义性和支配原则如:classA{

public:

voidf();};classB{

public:

voidf();

voidg();};classC:publicA,publicB{

public:

voidg();

voidh();};Cobj;则对函数f()的访问是二义的:obj.f();//无法确定访问A中或是B中的f()

如:classA{则对函数f()的访问是二义的:obj. 使用基类名可避免这种二义: obj.A::f();//A中的f(); obj.B::f();//B中的f(); C类的成员访问f()时也必须避免这种二义。 以上这种用基类名来控制成员访问的规则称为支配原则。 例如:

obj.g();//隐含用C的g() obj.B::g();//用B的g() 以上两个语句是无二义的。

使用基类名可避免这种二义: 成员的访问权限不能区分有二义性的同名成员:classA{

public:

voidfun();};classB{

protected;

voidfun();};classC:publicA,publicB{}; 虽然类C中的两个fun()函数,一个公有,一个私有,但:Cobj;

obj.fun(); //错误,仍是二义的 成员的访问权限不能区分有二义性的同名成员: 如果同一个成员名在两个具有继承关系的类中进行了定义,那么,在派生类中所定义的成员名具有支配地位。在出现二义性时,如果存在具有支配地位的成员名,那么编译器将使用这一成员,而不是给出错误信息。以上面的代码为例,在类A和类B中都定义了具有相同参数的成员函数a,这样,尽管类D中可以以两种方式来解释成员函数名a——即来自类B的成员函数a和来自类C的成员函数a,但是,按照刚才所说的规则,类B的成员名a相比类A的成员名a(即是类C中的成员名a)处于支配地位,这样,编译器将调用类B的成员函数a,而不产生二义性的错误。

如果同一个成员名在两个具有继承关系的类中进行了定义,那么2.同一基类被多次继承产生的二义性 由于二义的原因,一个类不能从同一类直接继承二次或更多次。如: classderived:publicbase,publicbase{…}是错的。 如果必须这样,可以使用中间类。 然而,尽管可以使用作用域限定符来解决二义性的问题,但是仍然不建议这样做,在使用多重继承机制时,最好还是保证所有的成员都不存在二义性问题。

2.同一基类被多次继承产生的二义性

赋值兼容规则 赋值兼容规则是指:在公有派生的情况下,一个派生类的对象可用于基类对象适用的地方。赋值兼容规则有三种情况(假定类derived由类base派生): (1)派生类的对象可以赋值给基类的对象。 derivedd; baseb; b=d; (2)派生类的对象可以初始化基类的引用。 derivedd; base&br=b;赋值兼容规则

(3)派生类的对象的地址可以赋给指向基类的指针。 derivedd; base*pb=&d; (3)派生类的对象的地址可以赋给指向基类的指针。

虚基类 当某类的部分或全部直接基类是从另一个共同基类派生而来时,这些直接基类中从上一级基类继承来的成员就拥有相同的名称,也就是说,这些同名成员在内存中存在多个副本。而多数情况下,由于它们的上一级基类是完全一样的,在编程时,只需使用多个副本的任一个。 C++语言允许程序中只建立公共基类的一个副本,将直接基类的共同基类设置为虚基类,这时从不同路径继承过来的该类成员在内存中只拥有一个副本,这样有关公共基类成员访问的二义性问题就不存在了。

虚基类 当某类的部分或全部直接基类是从另一个共同基类

虚基类的引入 如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。

引进虚基类的真正目的是为了解决二义性问题。当基类被继承时,在基类的访问控制保留字的前面加上保留字virtual来定义。

如果基类被声明为虚基类,则重复继承的基类在派生类对象实例中只好存储一个副本,否则,将出现多个基类成员的副本。

虚基类的引入 虚基类说明格式如下: virtual<继承方式><基类名> 其中,virtual是虚基类的关键字。虚基类的说明是用在定义派生类时,写在派生类名的后面。

引进虚基类后,派生类(即子类)的对象中只存在一个虚基类的子对象。当一个类有虚基类时,编译系统将为该类的对象定义一个指针成员,让它指向虚基类的子对象。该指针被称为虚基类指针。

虚基类说明格式如下: 注意:如果一个派生类从多个基类派生,而这些

温馨提示

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

评论

0/150

提交评论