第一节类的继承与派生一、基本概念继承是面向对象程序设计的一个特性,所谓继承就是在已有类的基础上创建新的类,新类可以从一个或多个已有类中继承成员函数或数据成员,而且新类还可以重新定义或加进新的数据和函数。
其中,已有类称为基类或父类,新类称为派生类或子类。
在现实世界中许多事物都具有继承性。
例如:“汽车”这个类中包括了许多类型,有运输汽车、专用汽车;运输汽车中又包括客车、货车…….;专用汽车中又包括巡逻车、消防车、救护车……..;所有这些类型的车都具有汽车的共同特性即都有发动机、车身、轮胎等共性,还都是自行驱动的。
而客车和货车又有所不同,客车用来载客,货车用来拉货,它们有自己不同于其它车的特性,这就是继承。
我们把汽车称为基类,把运输汽车、客车、货车称为派生类。
通过继承,派生类不仅拥有了基类的属性和行为,而且具有不同于它类的自己的特点。
二、派生类的定义与构成当你去水果店买水果的时候,你经常会发现很多同类水果又有了新的品种。
比如,“李子”既小又涩,嫁接在梨树上后长出来的李子却硕大、香甜、清脆,比没有嫁接的李子好吃,但它还是李子家族中的一员;所以,可以认为“嫁接李子”是从“李子”中派生出来的。
当然,可以把“李子”嫁接在梨树上,也可以嫁接在苹果树上,结出来的都是“李子”,但是各自味道不同。
所谓派生就是从已有类中产生一个新的子类。
基类就是已存在的可以派生新类的类,如下图中的A、D、E都是基类。
派生类就是由基类派生出来的新类,如下图中的B、C、F都是派生类。
1. 单继承派生类的定义格式class <派生类名> : <继承方式> <基类名>{派生类成员的定义;};其中,“派生类名”是新定义的一个类的名字,它是从“基类名”中派生的,并且按指定的“继承方式”派生。
例如:class peach 多继承派生类的定义格式class <派生类名> :<继承方式1> <基类名>,<继承方式2> <基类名>, …….{派生类成员的定义;};多继承与单继承在定义格式的区别仅在于它们的基类个数不同,单继承的基类只有一个,而多继承的基类有多个,相邻两个基类之间用逗号间隔,每个基类名前都应有一个该基类的继承方式的说明符。
例如:class peach //定义基类:peach{datatype color , shape ;};class apple //定义基类:peach{datatype color, shape , weight ;};class sweetpeach : public peach, public apple // 多继承{datatype color, shape, taste;};类sweetpeach 同时继承自类peach 和类apple,这就是多继承。
3.继承的作用有的读者可能会问为什么要有继承,继承有什么好处,继承的作用是什么为了解决这些疑问,我们一起来分析以下例子,从中领悟继承的奥妙。
【例10-1-1】分析以下代码。
声明一个person 类,它包含的成员有name(姓名)、age (年龄)、gender(性别),和output函数,具体定义如下:class person{public :char name[8] ;int age;char gender ;public :void output() { }};现在要声明一个student类,它包含的成员有name(姓名),age(年龄),gender(性别),department(系),stuno(学号),address(住址),和output函数,具体定义如下:class student{public :char name[8] ;int age;char gender;char department[20] ;int stuno;int address;public :void output() { }};从这两个类的声明中可以看出,它们中有些成员数据和成员函数是相同的。
这样就存在代码的重复,为了提高代码的可重用性,就引入了继承。
即,如果student类以共有继承的方式继承person类,那么student类就可以直接使用person类中的共有成员如name, gander,age和output() 函数,这样在student类中就不需要再定义与person类中相同的变量了,只定义person类中没有的在student类中需要的变量。
具体实现如下:class student : public person // student共有继承person类{public :char department[20] ;int stuno ;int address ;public :void output() { }};提示student 类称为派生类,person类成为基类;关键字public 的作用是说明派生类公有继承了基类中的所有成员,即派生类可以直接访问基类的成员;继承可以使代码得以重用,提高工作效率。
三、派生类访问基类成员通过前面的学习大家都知道基类的成员有public(公有)、protected(保护)、private(私有)3种访问属性,基类的自身成员可以对基类中任何一个其他成员进行访问,但是通过基类的对象就只能访问该类的公有成员。
派生类可以继承基类中除了构造函数和析构函数之外的全部成员,但是这些成员的访问属性在派生过程中是可以调整的。
从基类继承来的成员在派生类中的访问属性是由继承方式控制的。
不同的继承方式导致原来具有不同的访问属性的基类成员在派生类的访问属性也有所不同。
在派生类中,从基类继承来的成员可以访问属性有4种:不可直接访问的成员、public (公有成员)、protected(保护成员)、private(私有成员)。
1.三种继承方式的声明public 公有继承公有继承:在定义一个派生类时将基类的继承方式指定为public 的继承方式。
例如:class student : public person { }private 私有继承私有继承:在定义一个派生类时将基类的继承方式指定为private的继承方式。
例如:class student : private person { }protected 保护继承保护继承:在定义一个派生类时将基类的继承方式指定为protected的继承方式。
例如:class student : protected person { }2.三种继承方式的区别如表1指明了三种继承方式的区别,即派生类对基类成员的访问能力。
表 1 三种继承方式的区别在基类中的访问属性继承方式在派生类中的访问属性private public不可直接访问private private不可直接访问private protected不可直接访问public public publicpublic private privatepublic protected protectedprotected public protectedprotected private privateprotected protected protected提示在任何继承方式中基类中的私有成员都不允许派生类继承,即在派生类中是不可直接访问基类中的私有成员。
当类的继承方式为公有继承时:基类中的所有公有成员在派生类中仍为公有成员;基类中的所有保护成员在派生类中仍为保护成员。
当类的继承方式为私有继承时:基类中的所有公有成员在派生类中都为私有成员;基类中的所有保护成员在派生类中都为私有成员。
当类的继承方式为保护继承时:基类中的所有公有成员在派生类中都为保护成员;基类中的所有保护成员在派生类中仍为保护成员。
派生类对基类成员的访问形式主要有以下两种:(1) 内部访问:由派生类中的新增成员对从基类继承来的成员的访问。
(2) 对象访问:在派生类外部,通过派生类的对象对从基类继承的成员的访问。
现在分别讨论在公有继承、私有继承、保护继承这3种继承方式下,派生类对基类成员的访问规则。
一、公有继承【例1】分析以下程序。
源代码:#include <>#include <>class Base{private:int pvx; //pvx为基类私有变量protected :int pty; //pty为基类保护变量public :float puf; //puf为基类公有变量void Setxy(int q, int u, float w) //Setxy()为基类公有函数{pvx = q ; pty = u; puf = w;}void Output() //Output()为基类公有函数{cout << "class Base output "<< endl;cout << "pvx= " << pvx << endl;cout << "pty= " << pty << endl;cout << "puf= " << puf << endl;}};class Derive : public Base //公有单继承{private :float pvz;public :void Setvalue(int x, int y, float f, float z){Setxy(x, y, f);pvx = x; //非法访问,基类中的pvx为private属性,不能被继承pty = y; //合法访问puf = f; //合法访问pvz = z;}void Print(){cout << "pvx= " << pvx << endl;// 非法访问,在基类中pvx为私有成员cout << "class Derive output " << endl;cout << "pty= "<<pty << endl; // 合法访问,在基类中pvy为保护成员cout << "puf= "<<puf << endl; // 合法访问,在基类中puf为公有成员cout << "pvz= "<<pvz << endl; // 合法访问,pvz为派生类自己的成员}};void main(){Derive obj;(3,5, , ;();();cout << "puf= " << << endl; //合法访问,puf为基类公有成员cout<<<<endl; // 非法访问,类的外部不能访问为基类保护成员ptysystem("pause");}运行输出:class Base outputpvx= 3pty= 5puf=class Derive outputpty= 5puf=pvz=puf=【简要分析】①“class Derive : public Base { }”表明这是一个公有继承的例子,基类Base中有3个变量和两个函数:私有变量pvx、保护变量pty、公有变量puf和公有函数Setxy()、Output()。