开篇:润墨网以专业的文秘视角,为您筛选了一篇C++中类继承方式的讨论范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!
摘要:继承是c++面向对象程序设计中的重要概念,也是类的特性之一。通过继承可以循序渐进的接近对象的本质,同时也在编程中提高了代码的重用率,受到广泛的运用。笔者在教授C++程序设计的过程中,针对类的特性,绘制了类图,并应用类图来讲授类继承的三种方式。有图形的配合,形象生动,降低了学生的理解难度,收到学生的欢迎。
关键词:类;类图;继承;对象;重用率
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)12-2781-05
1类图的概念
类是一种用户自定义的类型,它和基本类型,如浮点型、整型,有类似的特征。同样,我们也可以声明某个类类型的变量,这个变量就称为类的对象,声明对象的过程叫做类的实例化。类和基本类型的区别在于,类类型中同时包含了对数据进行操作的函数。
类的成员可以有public(公有)、protected(保护)和private(私有)三种访问控制属性,外界只能访问类的公有成员。为了形象的描述类,笔者根据类封装的特性在教学过程中设计了一个称为“类图”的图形。如图1所示。
图1类内部成员访问示意图
外框①表示类是数据成员和函数成员的封装。箭头②表示外界能访问类的公有成员。方框③包含类的公有成员,表示类的外部接口。小箭头④表示类的公有成员可以访问类的保护和私有成员。方框⑤包含类私有和保护成员,表示类私有和保护成员外界不能直接访问。
通过类图我们可以很清楚的看到类成员的访问权限。
2类的继承和派生
面向对象的程序设计提供了类的继承机制,该机制自动地为一个类提供来自另一个类的操作和属性,这使得程序员只需要在新类中添加已有类中没有的成员来建立新类。以原有的类为基础产生新的类,我们就说新类继承了原有的类,或者说从原有类派生出新类。在这个过程中,原有的类我们称为基类,新类我们称为派生类(或称为父类和子类)。
在C++中,声明派生类的一般形式为:
class派生类名:继承方式基类名1,继承方式基类名2, ,继承方式基类名n{
派生类的成员声明;
};
在C++程序设计中,生成一个类的派生类,需要指定基类的类名,继承方式和新增加的成员。继承方式规定了派生类中从基类继承的成员的访问控制权限。继承方式有公有继承、保护继承和私有继承三种方式,其关键字分别为public、protected和private。派生类成员指除了从基类继承来的所有成员之外,自己扩充的数据和函数成员。
例如已经声明一个学生类Student,下面的语句声明了一个从学生类派生而来的研究生类GraduateStudent:
class GraduateStudent : public Student
{
public:
GraduateStudent( );
~GraduateStudent( );}
;
派生类由基类除构造函数和析构函数以外的全部成员和派生类新增成员组成。那么基类成员在派生类中的访问控制属性如何呢?这个由派生时的继承方式决定呢。
下面我们将讨论不同继承方式时派生类中基类成员的访问控制属性,并绘制派生类的“类图”。
3继承方式
在这里我们首先定义一个基类Point(点)类。Point(点)类有两个数据成员:x坐标和y坐标。//Point.h
class Point
{
private:float x,y;
protected:float GetX2( ){return x*x;}
float GetY2( ){return y*y;}
public:void Start(float xx=0, float yy=0) {x=xx; y=yy;}
void Move(float xOf, float yOf) {x=y+xOf ; y=y+yOf;}
float GetX( ){return x;}
float GetY( ){return y;}
};
Point类用类图表示如下:
图2Point类图
由Point类派生出新类Circle(圆)类。圆是由圆心和半径构成的,圆的圆心具备了Point类的全部特征,同时圆自身也有一些特点,比如有半径等。我们希望能够访问圆心的坐标,能够获得半径的大小。
接下来我们讨论对于三种继承方式,Circle(圆)类分别需要怎样如何设计才能达到上述要求,并画出类图。
1)公有继承
当类的继承方式为公有继承的时候,基类的public(公有)和protected(保护)成员在派生类中访问权限不变,而基类的private(私有)成员在派生类中不可直接访问。
表1公有继承在派生类中的访问权限
公有继承的派生类类图如下所示:
图3公有继承的派生类类图
[例1-1] Point类的公有继承。
#include”Point.h”
class Circle :public Point//派生类声明部分
private: float r;
public:void Start(float X, float Y, float R){Point::Start(X,Y); r=R;}
float GetR(){return r;}
};
这里派生类Circle继承了基类Point,因此派生类Circle吸收了基类Point除默认的构造函数和默认的析构函数以外的所有成员。继承方式为公有继承,所以基类中的公有成员和保护成员在派生类中访问属性保持原样,基类中的私有成员在派生类中不可直接访问。
Circle类中继承的获得圆心坐标的函数(GetX()和GetY())访问控制属性是公共的,所以只需添加获得半径的函数GetR()即可。
公有继承后的Circle类用类图表示如下:
图4 Circle类图
Circle类继承了Point类的成员,实现了代码的重用,同时通过添加新的成员,加入了自身的特性,实现了代码的扩充。公有继承是类的继承中用的最多的继承方式。
2)私有继承
当类的继承方式为私有继承的时候,基类中的public(公有)和protected(保护)成员被吸收后成为派生类的私有成员,而基类的private(私有)成员在派生类中不可直接访问。
表2私有继承在派生类中的访问属性
私有继承的派生类类图如下所示:
图5私有继承的派生类类图
我们将例1-1中的继承方式改为私有继承。派生类Circle继承了基类Point,因此派生类Circle吸收了基类Point除默认构造函数和默认析构函数以外的所有成员。继承方式为私有继承,所以基类中的公有成员和保护成员在在派生类中都变成了私有成员,基类原来的对外接口全部被隐藏,外部使用者不能通过派生类对象访问基类原来的任何成员。派生类的新增成员可以访问从基类继承过来的公有成员和保护成员。
[例1-2] Point类的私有继承。
经过私有继承以后,从基类继承的成员都变成了派生类的私有成员或不可直接访问的成员,如果进一步派生的话,基类全部成员就无法在新的派生类中直接访问。因此,私有继承之后,基类的成员就无法在以后的派生类中直接发挥作用,相当于终止了基类的功能,为了保证基类的原来的对外接口特征在派生类中也存在,常常在派生类中重新声明同名的成员。
本例中,私有继承后,基类的成员函数GetX()、GetY()和Move()均变成了派生类的私有函数成员,外界不能直接访问。为了在派生类中仍能访问圆心坐标,我们可以在Circle类中添加以上三个函数成员。则派生类的声明可以改为:
#include”Point.h”
ClassCircle: private Point//派生类声明部分
{
private:float r;
public:void Start(float X, float Y, float R){Point::Start(X,Y); r=R;}
float GetR(){return r;}
void Move(float xOf, float yOf){Point::Move(xOf,yOf);}
float GetX(){return Point::GetX();}
float GetY(){return Point::GetY();}
};
公有继承后的Circle类用类图表示如下:
图6 Circle类图
Circle类中继承的获得圆心坐标的函数(GetX()和GetY())访问控制属性是私有的,派生类对象不能直接访问,所以在新增成员除了需要添加获得半径的函数GetR(),还需要添加获得圆心坐标的函数(GetX()和GetY())。
3)保护继承
当类的继承方式为保护继承的时候,基类中的public(公有)和protected(保护)成员被吸收后成为派生类的保护成员,而基类中的private(私有)成员在派生类中不可直接访问。
表3保护继承在派生类中的访问属性
保护继承的派生类的类图如下所示:
图7保护继承的派生类类图
我们将例1-1中的继承方式改为保护继承。派生类Circle继承了基类Point,因此派生类Circle吸收了基类Point除默认构造函数和默认析构函数以外的所有成员。继承方式为保护继承,所以基类中的公有成员和保护成员在在派生类中都变成了保护成员,基类原来的对外接口全部被隐藏,外部使用者不能通过派生类对象访问基类原来的任何成员。派生类的新增成员可以访问从基类继承过来的公有成员和保护成员。
[例1-3] Point类的保护继承。
经过保护继承以后,从基类继承的成员都变成了派生类的保护成员或不可直接访问的成员。因此,保护继承之后,基类的成员就无法在以后的派生类中直接发挥作用,为了保证基类的原来的对外接口特征在派生类中也存在,常常在派生类中重新声明同名的成员。
本例中,保护继承后,基类的成员函数GetX()、GetY()和Move()均变成了派生类的保护函数成员,外界不能直接访问。为了在派生类中仍能访问圆心坐标,我们可以在Circle类中添加以上三个函数成员。则派生类的声明可以改为:
#include”Point.h”
class Circle: protected Point
{
private:float r;
public:void Start(float X, float Y, float R){Point::Start(X,Y); r=R;}
float GetR(){return r;}
void Move(float xOf, float yOf){Point::Move(xOf,yOf);}
float GetX(){return Point::GetX();}
float GetY(){return Point::GetY();}
};
保护继承后的Circle类用类图表示如下:
图8 Circle类图
Circle类中继承的获得圆心坐标的函数(GetX()和GetY())访问控制属性是保护的,派生类对象不能直接访问,所以在新增成员除了需要添加获得半径的函数GetR(),还需要添加获得圆心坐标的函数(GetX()和GetY())。
4)私有继承和保护继承的区别
从类图上看,类保护继承和私有继承似乎一样:基类私有成员在派生类中不能直接访问,基类的公有成员和保护成员可以被派生类新增成员访问,外部使用者不能通过对象直接调用基类它们。但是,当以派生类作为新的基类继续派生的时候,二者的区别就出现了。
假设Point类分别以私有和保护两种继承方式派生出Circle类,再在Circle类的基础上以公共继承的方式派生出圆柱体类Cylin der。仔细分析两种条件下的圆柱Cylinder类的成员,我们会发现Point类的公共成员在Cylinder类中访问控制属性不同。
//Cylinder.h
#include”Circle.h”
class Cylinder: public Circle
{
private:float h;
public:float GetH() {return h;}
};
参考文献:
[1]侯俊杰.深入浅出MFC[M].武汉:华中科技大学出版社,2003.
[2]钱能.C++程序设计教程[M].北京:清华大学出版社,1999.
[3]郑莉,董渊.C++语言程序设计[M].北京:清华大学出版社,2001.
[4]萨师煊,王珊.数据库系统概述[M].3版.北京:高等教育出版社,2002.
[5] Date C J.数据库系统导论[M].7版.北京:机械工业出版社,2000,10.