工信版(中职)编程语言基础------C++模块8教学课件.ppt
Y CF(中职)编程语言基础-C+模块8 教学课件模块8继承与派生 任务1继承概述 任务2派生类 任务3单继承 任务4多继承 任务5派生关系中的二义性 任务6虚基类返回任务1继承概述 8.1.1 继承 继承是现实世界普遍存在的现象。例如,子女会继承父母的特点,同 继承是现实世界普遍存在的现象。例如,子女会继承父母的特点,同时又有自己的特点。对老产品进行改进形成新产品,新产品继承老产 时又有自己的特点。对老产品进行改进形成新产品,新产品继承老产品的一些特征,同时又有新的改进。继承也被用于程序设计中。通过 品的一些特征,同时又有新的改进。继承也被用于程序设计中。通过继承可以在原有类的基础上建立新类,新类继承原有类的内容,使程 继承可以在原有类的基础上建立新类,新类继承原有类的内容,使程序代码可以重用,提高程序设计效率。序代码可以重用,提高程序设计效率。继承是一个进程,通过继承,一个对象可以获得另一个对象的属性。继承是一个进程,通过继承,一个对象可以获得另一个对象的属性。更严格地说,一个对象可以继承属性的集合,并可向其中加人属于自 更严格地说,一个对象可以继承属性的集合,并可向其中加人属于自己的一些特征。在 己的一些特征。在C+C+语言中,继承是一个十分重要的概念,因为继 语言中,继承是一个十分重要的概念,因为继承允许一个对象支持多层分类的概念。很多信息通过多层分类变得容 承允许一个对象支持多层分类的概念。很多信息通过多层分类变得容易管理。易管理。)下一页 返回任务1继承概述 例如 例如:楼房是建筑物中的一部分,建筑物又是结构的一部分,结构又是 楼房是建筑物中的一部分,建筑物又是结构的一部分,结构又是建造这一概念中的一部分。在这种情况下,子类继承了父类的所有属 建造这一概念中的一部分。在这种情况下,子类继承了父类的所有属性,并加人了子类所特有的属性。如果不使用多层分类的概念,对每 性,并加人了子类所特有的属性。如果不使用多层分类的概念,对每个对象的清晰描述都要包括其全部属性。而采用继承来描述一个对象 个对象的清晰描述都要包括其全部属性。而采用继承来描述一个对象时,只需在通用类特征的基础上添加该对象的一些特有属性即可。这 时,只需在通用类特征的基础上添加该对象的一些特有属性即可。这样一来,由继承得到的对象是惟一的,因此,继承在面向对象程序设 样一来,由继承得到的对象是惟一的,因此,继承在面向对象程序设计中的作用十分重要。计中的作用十分重要。类的继承是 类的继承是C+C+语言的一种重要机制,该机制自动为一个类提供来自 语言的一种重要机制,该机制自动为一个类提供来自另一个类的操作和数据结构。继承可以使程序设计人员在一个一般类 另一个类的操作和数据结构。继承可以使程序设计人员在一个一般类的基础上很快建立一个新的类,而不必从零开始设计每个类。的基础上很快建立一个新的类,而不必从零开始设计每个类。)上一页 下一页 返回任务1继承概述 8.1.2 继承的相关说明 关于继承的几点说明。关于继承的几点说明。(1)(1)如果子类继承了父类,则子类自动具有父类的全部数据成员 如果子类继承了父类,则子类自动具有父类的全部数据成员(数 数据结构 据结构)和成员函数 和成员函数(功能 功能););但是,子类对父类的成员的访问有所限制。但是,子类对父类的成员的访问有所限制。(2)(2)子类可以定义自己的成员 子类可以定义自己的成员:数据成员和成员函数。数据成员和成员函数。(3)(3)基类、派生类或父类、子类都是相对的。一个类派生出的新的类 基类、派生类或父类、子类都是相对的。一个类派生出的新的类就是派生类。派生类一也可以被其他类继承,这个派生类同时一也是 就是派生类。派生类一也可以被其他类继承,这个派生类同时一也是基类。基类。继承类别包括公有继承、私有继承和保护继承。继承类别包括公有继承、私有继承和保护继承。上一页 下一页 返回任务1继承概述 8.1.3 类的继承方式 1.1.公有继承 公有继承 派生时用 派生时用public public 作继承方式。作继承方式。基类的公有段 基类的公有段(public)(public)成员被继承为公有的。成员被继承为公有的。基类的私有段 基类的私有段(private)(private)成员在派生类中不可见。成员在派生类中不可见。基类的保护段 基类的保护段(protected)(protected)成员被继承为保护的。成员被继承为保护的。2.2.私有继承 私有继承 派生时用 派生时用private private 作继承方式。作继承方式。基类的公有段 基类的公有段(public)(public)成员被继承为私有的。成员被继承为私有的。基类的私有段 基类的私有段(private)(private)成员在派生类中不可见。成员在派生类中不可见。基类的保护段 基类的保护段(protected)(protected)成员被继承为私有的。成员被继承为私有的。上一页 下一页 返回任务1继承概述 3.3.保护继承 保护继承 派生时用 派生时用protected protected 作继承方式。作继承方式。基类的公有段 基类的公有段(public)(public)成员被继承为保护的。成员被继承为保护的。基类的私有段 基类的私有段(private)(private)成员在派生类中不可见。成员在派生类中不可见。基类的保护段 基类的保护段(protected)(protected)成员被继承为保护的。成员被继承为保护的。注意以下几点。注意以下几点。)(1)(1)无论哪种继承方式,基类中的 无论哪种继承方式,基类中的private private 成员在派生类中都是不可见的。成员在派生类中都是不可见的。换句话说,基类中的 换句话说,基类中的private private 成员不允许外部函数或派生类中的任何成 成员不允许外部函数或派生类中的任何成员访问。员访问。上一页 下一页 返回任务1继承概述(2 private(2 private 派生确保基类中的方法只可以让派生类对象中的方法间接 派生确保基类中的方法只可以让派生类对象中的方法间接使用,而不能被外部使用。使用,而不能被外部使用。(3)public(3)public 派生使得派生类对象和外部都可以直接使用基类中的方 派生使得派生类对象和外部都可以直接使用基类中的方法,除非这些方法已被重新定义。法,除非这些方法已被重新定义。(4)protected(4)protected 成员是一种血缘关系内外有别的成员,它对派生对象 成员是一种血缘关系内外有别的成员,它对派生对象来说,是公开成员,可以访问 来说,是公开成员,可以访问;对血缘外部来讲,和 对血缘外部来讲,和private private 成员一样 成员一样被隐蔽。被隐蔽。上一页 下一页 返回任务1继承概述(5)private(5)private 派生使得基类的非私有成员都成为派生类中的私有成员 派生使得基类的非私有成员都成为派生类中的私有成员;protected;protected 派生使基类中的非私有成员的访问属性在派生类中都降为 派生使基类中的非私有成员的访问属性在派生类中都降为保护的 保护的public public 派生使得基类的非私有成员的访问属性在派生类中保持 派生使得基类的非私有成员的访问属性在派生类中保持不变。不变。不同继承方式的结果见 不同继承方式的结果见 表 表8-1 8-1.上一页 返回任务2派生类 8.2.1 派生类的定义 一般情况下,继承的进程起源于一个基类的定义,基类定义了其所有 一般情况下,继承的进程起源于一个基类的定义,基类定义了其所有派生类的公有属性。从本质上讲,基类具有同一类集合中的公共属性,派生类的公有属性。从本质上讲,基类具有同一类集合中的公共属性,派生类继承了这些属性,并且增加了自己特有的属性。从任何已存在 派生类继承了这些属性,并且增加了自己特有的属性。从任何已存在的类继承的实质就是建造新的派生类。一也就是说,类继承可以从一 的类继承的实质就是建造新的派生类。一也就是说,类继承可以从一个类即基类中继承该基类的成员,并增加新的成员。个类即基类中继承该基类的成员,并增加新的成员。继承其他类属性的类称为派生类,又称为子类。那么在原有类基础 继承其他类属性的类称为派生类,又称为子类。那么在原有类基础上建立的新类也可以称之为派生类或子类,原有类称为子类的父类或 上建立的新类也可以称之为派生类或子类,原有类称为子类的父类或基类,一也可称为超类。子类和父类形成类的层次和继承关系。由于 基类,一也可称为超类。子类和父类形成类的层次和继承关系。由于子类在父类的基础上建立,因此子类继承了父类的特性和功子类除了 子类在父类的基础上建立,因此子类继承了父类的特性和功子类除了拥有父类的特性和功能外,还可以增加自己的特性和功能。拥有父类的特性和功能外,还可以增加自己的特性和功能。下一页 返回任务2派生类 C+C+中定义派生类的语法格式如下 中定义派生类的语法格式如下:class class:新增私有成员声明语句列表 新增私有成员声明语句列表 public:public:新增公有成员声明语句列表 新增公有成员声明语句列表 protected:protected:新增保护成员声明语句列表 新增保护成员声明语句列表;上一页 下一页 返回任务2派生类“继承方式 继承方式”即派生类的访问控制方式,用于控制基类中声明的成员 即派生类的访问控制方式,用于控制基类中声明的成员在多大的范围内能被派生类的用户访问。每一个继承方式,只对紧随 在多大的范围内能被派生类的用户访问。每一个继承方式,只对紧随其后的基类进行限定。其后的基类进行限定。继承方式包括 继承方式包括3 3 种 种:公有继承 公有继承public;public;私有继承 私有继承private;private;保护继 保护继承 承protected protected。若不显式给出继承方式关键字,系统则默认为私有继承。若不显式给出继承方式关键字,系统则默认为私有继承(private(private。类的继承方式指定了派生类成员以及类外对象对于从基类。类的继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限。继承来的成员的访问权限。从己有类派生出的新类,除了能从基类继承所有成员之外,还可以 从己有类派生出的新类,除了能从基类继承所有成员之外,还可以在派生类内完成以下几种功能。在派生类内完成以下几种功能。)上一页 下一页 返回任务2派生类(1)(1)可以增加新的数据成员。可以增加新的数据成员。(2)(2)可以增加新的成员函数。可以增加新的成员函数。(3)(3)可以重新定义基类中已有的成员函数。可以重新定义基类中已有的成员函数。(4)(4)可以改变现有成员的属性。可以改变现有成员的属性。继承方式决定了子类对父类的访问权限。有 继承方式决定了子类对父类的访问权限。有3 3 种继承方式 种继承方式:private:private,public,public 和 和protected,protected,默认为 默认为private,private,最常用的是 最常用的是public public 为了理解 为了理解G+G+如何根据已有类建立新类,请分析下面的程序。如何根据已有类建立新类,请分析下面的程序。上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 在类名 在类名B B 后 后public A public A 之前有一个冒号。冒号说明 之前有一个冒号。冒号说明B B 类根据 类根据A A 类建立,类建立,A A类是 类是B B 类的基类 类的基类(直接基类 直接基类),B),B 类可以继承 类可以继承A A 类的内容。关键字 类的内容。关键字public public 表 表明,基类 明,基类A A 的所有公有成员一也是派生类的公有成员。但基类 的所有公有成员一也是派生类的公有成员。但基类A A 的所 的所有私有成员仍只属于 有私有成员仍只属于A A 类,不被派生类 类,不被派生类B B 继承。继承。一个类可以有直接基类和间接基类。如果类 一个类可以有直接基类和间接基类。如果类A A 派生出类 派生出类B B,类,类B B 又派 又派生出类 生出类C C,则称类,则称类A A 是类 是类B B 的直接基类,类 的直接基类,类B B 是类 是类C C 的直接基类,类 的直接基类,类A A 是 是类 类C C 的间接基类。的间接基类。上一页 下一页 返回任务2派生类 8.2.2派生类的构造函数和析构函数 派生类继承了基类的成员,实现了代码的复用。但是,基类的构造函 派生类继承了基类的成员,实现了代码的复用。但是,基类的构造函数和析构函数不能被继承。在派生类中,如果对派生类新增成员进行 数和析构函数不能被继承。在派生类中,如果对派生类新增成员进行初始化,就必须由程序员针对实际需要加人新的构造函数。而且,对 初始化,就必须由程序员针对实际需要加人新的构造函数。而且,对所有从基类继承下来的成员的初始化工作,还是由基类的构造函数完 所有从基类继承下来的成员的初始化工作,还是由基类的构造函数完成,但必须在派生类中,对基类的构造函数所需的参数进行设置。同 成,但必须在派生类中,对基类的构造函数所需的参数进行设置。同样,对派生类对象的扫尾、清理工作也需要加人新的析构函数。样,对派生类对象的扫尾、清理工作也需要加人新的析构函数。上一页 下一页 返回任务2派生类 1.1.派生类的构造函数 派生类的构造函数 构造函数不能被继承,因此,派生类的构造函数必须通过调用基类 构造函数不能被继承,因此,派生类的构造函数必须通过调用基类的构造函数来初始化基类子对象。所以,在定义派生类的构造函数时,的构造函数来初始化基类子对象。所以,在定义派生类的构造函数时,除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数 除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数使基类的数据成员得以初始化。如果派生类中还有子对象,还应包含 使基类的数据成员得以初始化。如果派生类中还有子对象,还应包含对子对象初始化的构造函数。对子对象初始化的构造函数。上一页 下一页 返回任务2派生类 派生类构造函数的一般语法规则为 派生类构造函数的一般语法规则为:():):()1),基类名 基类名n()n),()1),(m(子对象参数表 子对象参数表m)m)上一页 下一页 返回任务2派生类 派生类构造函数执行的一般次序如下 派生类构造函数执行的一般次序如下:首先调用基类构造函数,调用 首先调用基类构造函数,调用顺序按照它们被继承时说明的顺序。然后调用子对象的构造函数,调 顺序按照它们被继承时说明的顺序。然后调用子对象的构造函数,调用顺序按照它们在类中的说明顺序。最后是派生类构造函数中的内容。用顺序按照它们在类中的说明顺序。最后是派生类构造函数中的内容。在实际应用中,使用派生类构造函数时应注意以下两个问题。在实际应用中,使用派生类构造函数时应注意以下两个问题。(1)(1)派生类构造函数的定义中可以省略对基类构造函数的调用,其条 派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有默认的构造函数或者根本没有定义构造函数。当 件是在基类中必须有默认的构造函数或者根本没有定义构造函数。当然,若基类中没有定义构造函数,派生类就不必负责调用基类构造函 然,若基类中没有定义构造函数,派生类就不必负责调用基类构造函数。数。(2)(2)当基类的构造函数使用一个或多个参数时,则派生类必须定义构 当基类的构造函数使用一个或多个参数时,则派生类必须定义构造函数,提供将参数传递给基类构造函数的途径。在某些情况下,派 造函数,提供将参数传递给基类构造函数的途径。在某些情况下,派生类构造函数的参数可能为空,仅起到传递参数的作用。生类构造函数的参数可能为空,仅起到传递参数的作用。上一页 下一页 返回任务2派生类 2.2.派生类的析构函数 派生类的析构函数 当对象被删除时,派生类的析构函数就被执行。当对象被删除时,派生类的析构函数就被执行。由于析构函数不能被继承,因此在执行派生类的析构函数时,基类 由于析构函数不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执 的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数的顺序正好相反。行基类的析构函数,其顺序与执行构造函数的顺序正好相反。上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 运行结果:运行结果:xy xy 在 在C+C+中,由于析构函数不能被继承,因此在执行派生类的析构函数 中,由于析构函数不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函 时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,其顺序与执行构造函数的顺序正好相反。数,再执行基类的析构函数,其顺序与执行构造函数的顺序正好相反。在此题的程序中,在主函数 在此题的程序中,在主函数main main 结束时,派生类 结束时,派生类Derived Derived 对象 对象ohj ohj 将被 将被删除,所以就会调用对象的析构函数。先调用派生类的析构函数,输 删除,所以就会调用对象的析构函数。先调用派生类的析构函数,输出 出x x,然后调用,然后调用 基类的析构函数,输出 基类的析构函数,输出Y Y。上一页 下一页 返回任务2派生类 8.2.3基类与派生类之间的关系(1)(1)派生类不仅拥有属于自己的数据成员与成员函数,而且还保持了 派生类不仅拥有属于自己的数据成员与成员函数,而且还保持了从基类继承来的数据成员与成员函数。同时派生类可对一些继承来的 从基类继承来的数据成员与成员函数。同时派生类可对一些继承来的函数重新定义,以适应新的要求。函数重新定义,以适应新的要求。(2)C+(2)C+中关于类的继承方式的规定,如 中关于类的继承方式的规定,如 表 表8-2 8-2 所示。所示。上一页 下一页 返回任务2派生类 按 按private private 方式继承 方式继承(即私有继承 即私有继承)时,基类中的公有成员和保护成员 时,基类中的公有成员和保护成员在派生类中皆变为私有成员。在派生类中皆变为私有成员。按 按public public 方式继承 方式继承(即公有继承 即公有继承)时,基类中的公有成员和保护成员 时,基类中的公有成员和保护成员在派生类中不变。在派生类中不变。无论按哪种继承方式继承,基类的私有成员在派生类中始终是不 无论按哪种继承方式继承,基类的私有成员在派生类中始终是不可访问的。这与私有成员的定义是一致的,符合数据封装的思想。可访问的。这与私有成员的定义是一致的,符合数据封装的思想。注意 注意:私有成员与不可访问成员是两个不同的概念。某个类的私有成 私有成员与不可访问成员是两个不同的概念。某个类的私有成员只能被该类的成员函数所访问,而类的不可访问成员甚至不能被该 员只能被该类的成员函数所访问,而类的不可访问成员甚至不能被该类的成员函数所访问。类的不可访问成员总是从某个基类派生来的,类的成员函数所访问。类的不可访问成员总是从某个基类派生来的,它或者是基类的私有成员,或者是基类的不可访问成员。它或者是基类的私有成员,或者是基类的不可访问成员。上一页 下一页 返回任务2派生类(3)(3)在 在C+C+中,可以根据需要定义多层的继承关系,一也可以从一个基 中,可以根据需要定义多层的继承关系,一也可以从一个基类派生出多个类来形成类的层次结构,在类的层次结构中,处于高层 类派生出多个类来形成类的层次结构,在类的层次结构中,处于高层的类表示最一般的特征,而处于底层的类则表示更具体的特征。在多 的类表示最一般的特征,而处于底层的类则表示更具体的特征。在多层继承关系中,基类与派生类的关系是相对的,例如 层继承关系中,基类与派生类的关系是相对的,例如:由类 由类A A 派生出类 派生出类B B,再由类,再由类B B 派生出类 派生出类C C。这里,类。这里,类B B 相对于类 相对于类A A 是派生类,而相对于 是派生类,而相对于类 类C C 则是基类,并称类 则是基类,并称类C C 是类 是类A A 的间接派生类,称类 的间接派生类,称类A A 是类 是类C C 的间接基 的间接基类,而称具有直接派生关系的两个类分别为直接派生类和直接基类。类,而称具有直接派生关系的两个类分别为直接派生类和直接基类。)上一页 下一页 返回任务2派生类【例 例8-1 8-1】类 类Build_1 Build_1 是一个关于楼房数据的类。它的数据成员有 是一个关于楼房数据的类。它的数据成员有posi_x,posi_y posi_x,posi_y 和 和area area,分别是楼房位置的经、纬度和建筑面积。它的,分别是楼房位置的经、纬度和建筑面积。它的函数成员只有 函数成员只有setl setl,用于设置数据成员,用于设置数据成员posi_ x,posi_y posi_ x,posi_y 和 和area area 的值。让 的值。让Build_ 1 Build_ 1 作为基类,再增加数据成员 作为基类,再增加数据成员hi hi 蜘、函数成员 蜘、函数成员set2 set2 和 和disp disp 来定义 来定义派生类 派生类Build_2 Build_2。上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 运行结果:运行结果:经度 经度:100:100 纬度 纬度:200:200 高度 高度:400:400 面积 面积:300:300上一页 下一页 返回任务2派生类 由此可见,派生类 由此可见,派生类Build Build 一中继承了基类 一中继承了基类Build_ 1 Build_ 1 中的数据成员 中的数据成员posi_x posi_x,posi_v,area(,posi_v,area(它们都是基类 它们都是基类Build_ 1 Build_ 1 中的 中的protected protected 成员 成员)和基类中的 和基类中的成员函数 成员函数setl(setl(它是基类的 它是基类的public;public;成员 成员),并同时增加了新的成员,并同时增加了新的成员height height和成员函数 和成员函数set2,disp set2,disp 8.2.4派生类对基类成员的访问 派生类对基类成员的访问能力如 派生类对基类成员的访问能力如 表 表8-3 8-3 所示。所示。从 从 表 表8-3 8-3 可以看出以下两点。可以看出以下两点。(1)(1)基类中的私有成员在派生类中是隐藏的,只能在基类内部访问。基类中的私有成员在派生类中是隐藏的,只能在基类内部访问。上一页 下一页 返回任务2派生类(2)(2)派生类中的成员不能访问基类中的私有成员,可以访问基类中的 派生类中的成员不能访问基类中的私有成员,可以访问基类中的公有成员和保护成员。公有成员和保护成员。此时派生类对基类中各成员的访问能力与继承方式无关,但继承方 此时派生类对基类中各成员的访问能力与继承方式无关,但继承方式将影响基类成员在派生类中的访问控制属性。基类中公有成员和保 式将影响基类成员在派生类中的访问控制属性。基类中公有成员和保护成员的访问控制属性将随着继承方式而改变 护成员的访问控制属性将随着继承方式而改变:派生类从基类公有继承 派生类从基类公有继承时,基类的公有成员和保护成员在派生类中仍为公有成员和保护成员 时,基类的公有成员和保护成员在派生类中仍为公有成员和保护成员;派生类从基类私有继承时,基类的公有成员和保护成员在派生类中都 派生类从基类私有继承时,基类的公有成员和保护成员在派生类中都改变为私有成员 改变为私有成员;派生类从基类保护继承时,基类的公有成员在派生类 派生类从基类保护继承时,基类的公有成员在派生类中改变为保护成员,基类的保护成员在派生类中则仍为保护成员。中改变为保护成员,基类的保护成员在派生类中则仍为保护成员。上一页 下一页 返回任务2派生类 派生类对基类成员的访问形式主要有以下两种。派生类对基类成员的访问形式主要有以下两种。(1)(1)内部访问 内部访问:由派生类中新增成员对基类继承来的成员的访问。由派生类中新增成员对基类继承来的成员的访问。(2)(2)对象访问 对象访问:在派生类外部,通过派生类的对象对从基类继承来的 在派生类外部,通过派生类的对象对从基类继承来的成员的访问。成员的访问。1.1.私有继承的访问规则 私有继承的访问规则 当类的继承方式为私有继承时,基类的 当类的继承方式为私有继承时,基类的public public 成员和 成员和protected protected 成员 成员被继承后作为派生类的 被继承后作为派生类的private private 成员,派生类的其他成员可以直接访问 成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。它们,但是在类外部通过派生类的对象无法访问。基类的 基类的private private 成员在私有派生类中是不可以直接访问的,所以无论 成员在私有派生类中是不可以直接访问的,所以无论是派生类成员还是通过派生类的对象,都无法直接访问从基类继承来 是派生类成员还是通过派生类的对象,都无法直接访问从基类继承来的 的private private 成员,但是可以通过基类提供的 成员,但是可以通过基类提供的public public 成员函数间接访问。成员函数间接访问。访问规则如 访问规则如 表 表8-4 8-4 所示。所示。上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 说明 说明:在这个例子中,由于是私有继承,所以在 在这个例子中,由于是私有继承,所以在main main 函数中不能对函 函数中不能对函数 数set(),print set(),print 进行访问。由于 进行访问。由于x,v x,v 是基类 是基类Foundation Foundation 中的私有成员,中的私有成员,所以在 所以在display)display)中不能对它进行访问,要使调用 中不能对它进行访问,要使调用display()display()输出三个数,输出三个数,可以改为如下形式 可以改为如下形式:上一页 下一页 返回任务2派生类 2.2.公有继承的访问规则 公有继承的访问规则 当类的继承方式为公有继承时,基类的 当类的继承方式为公有继承时,基类的public public 成员和 成员和protected protected 成员 成员继承到派生类中仍作为派生类的 继承到派生类中仍作为派生类的public public 成员和 成员和protected protected 成员,派生类 成员,派生类的其他成员可以直接访问它们。但是,类的外部使用者只能通过派生 的其他成员可以直接访问它们。但是,类的外部使用者只能通过派生类的对象访问继承来的 类的对象访问继承来的public public 成员。成员。基类的 基类的private private 成员在私有派生类中是不可直接访问的,所以无论是 成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是通过派生类的对象,都无法直接访问从基类继承来的 派生类成员还是通过派生类的对象,都无法直接访问从基类继承来的private private 成员,但是可以通过基类提供的 成员,但是可以通过基类提供的public public 成员函数间接访问它们。成员函数间接访问它们。访问规则如 访问规则如 表 表8-5 8-5 所示。所示。上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 说明 说明:在 在main main 函数中可以使用 函数中可以使用exam.set(),exam.print)exam.set(),exam.print)函数,因为它 函数,因为它们在继承类中为 们在继承类中为public public 成员,所以可以直接使用。成员,所以可以直接使用。3.3.保护继承的访问规则 保护继承的访问规则 当类的继承方式为保护继承时,基类的 当类的继承方式为保护继承时,基类的public public 成员和 成员和protected protected 成员 成员继承到派生类中都作为派生类的 继承到派生类中都作为派生类的protected protected 成员,派生类的其他成员可 成员,派生类的其他成员可以直接访问它们,但是类的外部使用者不能通过派生类的对象来访问 以直接访问它们,但是类的外部使用者不能通过派生类的对象来访问它们。它们。基类的 基类的private private 成员在私有派生类中是不可直接访问的,所以无论是 成员在私有派生类中是不可直接访问的,所以无论是派生类成员还是通过派生类的对象,都无法直接访问基类的 派生类成员还是通过派生类的对象,都无法直接访问基类的private private 成 成员。访问规则如 员。访问规则如 表 表8-6 8-6 所示。所示。上一页 下一页 返回任务2派生类【例 例8-4 8-4】上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类上一页 下一页 返回任务2派生类 上一页 下一页 返回任务2派生类 说明 说明:在 在main()main()中,由于 中,由于exam.set(),exam.print()exam.set(),exam.print()函数在继承类中为 函数在继承类中为protected protected 成员,不能用对象直接访问,把这两句注释掉就可以运行了。成员,不能用对象直接访问,把这两句注释掉就可以运行了。上一页 返回任务3单继承 在 在C+C+中,一个派生类既可以从一个基类派生,也可以从多个基类派 中,一个派生类既可以从一个基类派生,也可以从多个基类派生。从一个基类派生称为单继承,而从多个基类派生称为多重继承。生。从一个基类派生称为单继承,而从多个基类派生称为多重继承。本任务先介绍单继承。单继承的继承关系如 本任务先介绍单继承。单继承的继承关系如 图 图8-1 8-1。单继承声明语句的常用形式为 单继承声明语句的常用形式为:class class 派生类名 派生类名:访问方式基类名 访问方式基类名 数据成员和成员函数声明 数据成员和成员函数声明 说明以下几点。说明以下几点。(1)(1)派生类名由用户自己命名。派生类名由用户自己命名。(2)(2)在冒号 在冒号“:”:”后的内容告诉系统,这个派生类是从哪个基类派生 后的内容告诉系统,这个派生类是从哪个基类派生的以及在派生时的继承方式是什么。的以及在派生时的继承方式是什么。返回 下一页任务3单继承(3)“(3)“访问方式 访问方式”即继承方式,它可以为 即继承方式,它可以为public public 或 或private private。如果省略,。如果省略,则默认为 则默认为private private 方式。访问方式为 方式。访问方式为public public 时,这种继承称为公有继承 时,这种继承称为公有继承;而访问方式为 而访问方式为private private 时,这种继承则称为私有继承。时,这种继承则称为私有继承。(4)(4)基类名必须是程序中已有的一个类。基类名必须是程序中已有的一个类。(5)(5)大括号内的部分是派生类中新定义的成员。大括号内的部分是派生类中新定义的成员。【例 例8-5 8-5】单继承举例。单继承举例。上一页 下一页 返回任务3单继承上一页 下一页 返回任务3单继承上一页 下一页 返回任务3单继承 运行结果:运行结果:20 20上一页 下一页 返回任务3单继承 程序中,类 程序中,类A A 是基类,类 是基类,类B B 是从类 是从类A A 派生而来。派生类 派生而来。派生类B B 的成员函数 的成员函数g2 g2()()调用了基类 调用了基类A A 的成员函数 的成员函数f2()f2(),这种调用方法是正确的,因为基类,这种调用方法是正确的,因为基类A A中的公有成员也是派生类 中的公有成员也是派生类B B 的公有成员。但是,如果 的公有成员。但是,如果g2()g2()要访问变量 要访问变量i i,必须通过函数,必须通过函数f2()f2(),因为,因为i i 是 是A A 的私有变量,仍封装在基类 的私有变量,仍封装在基类A A 中,中,A A 的 的派生类不能直接访问这个变量。如果一个类的私有成员通过继承机制 派生类不能直接访问这个变量。如果一个类的私有成员通过继承机制就能变为公有成员,那么封装就没有意义了。就能变为公有成员,那么封装就没有意义了。上一页 返回任务4多继承 从多个基类派生的继承称为多继承或多重继承。也就是说,一个派生 从多个基类派生的继承称为多继承或多重继承。也就是说,一个派生类有多个直接基类。多继承的继承关系如 类有多个直接基类。多继承的继承关系如 图 图8-2 8-2 所示。所示。多继承声明语句的形式为 多继承声明语句的形式为:class class 派生类名 派生类名:访问方式基类名 访问方式基类名1 1,访问方式基类名,访问方式基类名2,.2,.数据成员和成员函数声明 数据成员和成员函数声明 例如 例如:class A class A 数据成员和成员函数声明 数据成员和成员函数声明 下一页 返回任务4多继承 class B class B 数据成员和成员函数声明 数据成员和成员函数声明 class C:public A,private B class C:public A,private B 数据成员和成员函数声明 数据成员和成员函数声明 上一页 下一页 返回任务4多继承 此例说明类 此例说明类C C 继承了类 继承了类A A 和类 和类B B。类。类C C 是一个多继承。类 是一个多继承。类A A 的成员被继 的成员被继承后,访问权限不变。类 承后,访问权限不变。类B B 的成员被继承后,成为类 的成员被继承后,成为类C C 的私有成员。的私有成员。类 类C C 虽然继承了类 虽然继承了类A A 和类 和类B B 的私有成员,但仍然不能直接访问它们。请 的私有成员,但仍然不能直接访问它们。请看下面的例子。看下面的例子。上一页 下一页 返回任务4多继承上一页 下一页 返回任务4多继承 类 类C C 对象的成员与类 对象的成员与类A A 和类 和类B B 成员的关系可用一个有向无环图表示,如 成员的关系可用一个有向无环图表示,如图 图8-3 8-3 所示。所示。箭头表示由谁派生而来。花括号内列出该类声明的成员。从图 箭头表示由谁派生而来。花括号内列出该类声明的成员。从图8-3 8-3 可 可以看出,以看出,C C 从 从A A 和 和B B 两个继承路径继承而来,每个继承可以视为一个单 两个继承路径继承而来,每个继承可以视为一个单继承。继承。上一页 下一页 返回任务4多继承上一页 下一页 返回任务4多继承上一页 下一页 返回任务4多继承上一页 下一页 返回任务4多继承 运行结果 运行结果:A:show()A A:show()A 中 中i=1 i=1 B:show()B B:show()B 中 中i=2 i=2 C:show()C C:show()C 中 中i=3 i=3上一页 返回任务5派生关系中的二义性 继承和派生把不同的类联系到一起,这里就产生了一个同名成员的处 继承和派生把不同的类联系到一起,这里就产生了一个同名成员的处理问题,下面我们分几种情形来介绍。理问题,下面我们分几种情形来介绍。8.5.1单一继承时基