張宇
摘要:繼承是C++面向?qū)ο蟪绦蛟O(shè)計中的重要概念,也是類的特性之一。通過繼承可以循序漸進的接近對象的本質(zhì),同時也在編程中提高了代碼的重用率,受到廣泛的運用。筆者在教授C++程序設(shè)計的過程中,針對類的特性,繪制了類圖,并應(yīng)用類圖來講授類繼承的三種方式。有圖形的配合,形象生動,降低了學(xué)生的理解難度,收到學(xué)生的歡迎。
關(guān)鍵詞:類;類圖;繼承;對象;重用率
中圖分類號:TP311文獻標識碼:A文章編號:1009-3044(2012)12-2781-05
1類圖的概念
類是一種用戶自定義的類型,它和基本類型,如浮點型、整型,有類似的特征。同樣,我們也可以聲明某個類類型的變量,這個變量就稱為類的對象,聲明對象的過程叫做類的實例化。類和基本類型的區(qū)別在于,類類型中同時包含了對數(shù)據(jù)進行操作的函數(shù)。
類的成員可以有public(公有)、protected(保護)和private(私有)三種訪問控制屬性,外界只能訪問類的公有成員。為了形象的描述類,筆者根據(jù)類封裝的特性在教學(xué)過程中設(shè)計了一個稱為“類圖”的圖形。如圖1所示。
圖1類內(nèi)部成員訪問示意圖
外框①表示類是數(shù)據(jù)成員和函數(shù)成員的封裝。箭頭②表示外界能訪問類的公有成員。方框③包含類的公有成員,表示類的外部接口。小箭頭④表示類的公有成員可以訪問類的保護和私有成員。方框⑤包含類私有和保護成員,表示類私有和保護成員外界不能直接訪問。
通過類圖我們可以很清楚的看到類成員的訪問權(quán)限。
2類的繼承和派生
面向?qū)ο蟮某绦蛟O(shè)計提供了類的繼承機制,該機制自動地為一個類提供來自另一個類的操作和屬性,這使得程序員只需要在新類中添加已有類中沒有的成員來建立新類。以原有的類為基礎(chǔ)產(chǎn)生新的類,我們就說新類繼承了原有的類,或者說從原有類派生出新類。在這個過程中,原有的類我們稱為基類,新類我們稱為派生類(或稱為父類和子類)。
在C++中,聲明派生類的一般形式為:
class派生類名:繼承方式基類名1,繼承方式基類名2, ,繼承方式基類名n{
派生類的成員聲明;
};
在C++程序設(shè)計中,生成一個類的派生類,需要指定基類的類名,繼承方式和新增加的成員。繼承方式規(guī)定了派生類中從基類繼承的成員的訪問控制權(quán)限。繼承方式有公有繼承、保護繼承和私有繼承三種方式,其關(guān)鍵字分別為public、protected和private。派生類成員指除了從基類繼承來的所有成員之外,自己擴充的數(shù)據(jù)和函數(shù)成員。
例如已經(jīng)聲明一個學(xué)生類Student,下面的語句聲明了一個從學(xué)生類派生而來的研究生類GraduateStudent:
class GraduateStudent : public Student
{
public:
GraduateStudent( );
~GraduateStudent( );}
;
派生類由基類除構(gòu)造函數(shù)和析構(gòu)函數(shù)以外的全部成員和派生類新增成員組成。那么基類成員在派生類中的訪問控制屬性如何呢?這個由派生時的繼承方式?jīng)Q定呢。
下面我們將討論不同繼承方式時派生類中基類成員的訪問控制屬性,并繪制派生類的“類圖”。
3繼承方式
在這里我們首先定義一個基類Point(點)類。Point(點)類有兩個數(shù)據(jù)成員: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(圓)類。圓是由圓心和半徑構(gòu)成的,圓的圓心具備了Point類的全部特征,同時圓自身也有一些特點,比如有半徑等。我們希望能夠訪問圓心的坐標,能夠獲得半徑的大小。
接下來我們討論對于三種繼承方式,Circle(圓)類分別需要怎樣如何設(shè)計才能達到上述要求,并畫出類圖。
1)公有繼承
當類的繼承方式為公有繼承的時候,基類的public(公有)和protected(保護)成員在派生類中訪問權(quán)限不變,而基類的private(私有)成員在派生類中不可直接訪問。
表1公有繼承在派生類中的訪問權(quán)限
公有繼承的派生類類圖如下所示:
圖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除默認的構(gòu)造函數(shù)和默認的析構(gòu)函數(shù)以外的所有成員。繼承方式為公有繼承,所以基類中的公有成員和保護成員在派生類中訪問屬性保持原樣,基類中的私有成員在派生類中不可直接訪問。
Circle類中繼承的獲得圓心坐標的函數(shù)(GetX()和GetY())訪問控制屬性是公共的,所以只需添加獲得半徑的函數(shù)GetR()即可。
公有繼承后的Circle類用類圖表示如下:
圖4 Circle類圖
Circle類繼承了Point類的成員,實現(xiàn)了代碼的重用,同時通過添加新的成員,加入了自身的特性,實現(xiàn)了代碼的擴充。公有繼承是類的繼承中用的最多的繼承方式。
2)私有繼承
當類的繼承方式為私有繼承的時候,基類中的public(公有)和protected(保護)成員被吸收后成為派生類的私有成員,而基類的private(私有)成員在派生類中不可直接訪問。
表2私有繼承在派生類中的訪問屬性
私有繼承的派生類類圖如下所示:
圖5私有繼承的派生類類圖
我們將例1-1中的繼承方式改為私有繼承。派生類Circle繼承了基類Point,因此派生類Circle吸收了基類Point除默認構(gòu)造函數(shù)和默認析構(gòu)函數(shù)以外的所有成員。繼承方式為私有繼承,所以基類中的公有成員和保護成員在在派生類中都變成了私有成員,基類原來的對外接口全部被隱藏,外部使用者不能通過派生類對象訪問基類原來的任何成員。派生類的新增成員可以訪問從基類繼承過來的公有成員和保護成員。
[例1-2] Point類的私有繼承。
經(jīng)過私有繼承以后,從基類繼承的成員都變成了派生類的私有成員或不可直接訪問的成員,如果進一步派生的話,基類全部成員就無法在新的派生類中直接訪問。因此,私有繼承之后,基類的成員就無法在以后的派生類中直接發(fā)揮作用,相當于終止了基類的功能,為了保證基類的原來的對外接口特征在派生類中也存在,常常在派生類中重新聲明同名的成員。
本例中,私有繼承后,基類的成員函數(shù)GetX()、GetY()和Move()均變成了派生類的私有函數(shù)成員,外界不能直接訪問。為了在派生類中仍能訪問圓心坐標,我們可以在Circle類中添加以上三個函數(shù)成員。則派生類的聲明可以改為:
#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類中繼承的獲得圓心坐標的函數(shù)(GetX()和GetY())訪問控制屬性是私有的,派生類對象不能直接訪問,所以在新增成員除了需要添加獲得半徑的函數(shù)GetR(),還需要添加獲得圓心坐標的函數(shù)(GetX()和GetY())。
3)保護繼承
當類的繼承方式為保護繼承的時候,基類中的public(公有)和protected(保護)成員被吸收后成為派生類的保護成員,而基類中的private(私有)成員在派生類中不可直接訪問。
表3保護繼承在派生類中的訪問屬性
保護繼承的派生類的類圖如下所示:
圖7保護繼承的派生類類圖
我們將例1-1中的繼承方式改為保護繼承。派生類Circle繼承了基類Point,因此派生類Circle吸收了基類Point除默認構(gòu)造函數(shù)和默認析構(gòu)函數(shù)以外的所有成員。繼承方式為保護繼承,所以基類中的公有成員和保護成員在在派生類中都變成了保護成員,基類原來的對外接口全部被隱藏,外部使用者不能通過派生類對象訪問基類原來的任何成員。派生類的新增成員可以訪問從基類繼承過來的公有成員和保護成員。
[例1-3] Point類的保護繼承。
經(jīng)過保護繼承以后,從基類繼承的成員都變成了派生類的保護成員或不可直接訪問的成員。因此,保護繼承之后,基類的成員就無法在以后的派生類中直接發(fā)揮作用,為了保證基類的原來的對外接口特征在派生類中也存在,常常在派生類中重新聲明同名的成員。
本例中,保護繼承后,基類的成員函數(shù)GetX()、GetY()和Move()均變成了派生類的保護函數(shù)成員,外界不能直接訪問。為了在派生類中仍能訪問圓心坐標,我們可以在Circle類中添加以上三個函數(shù)成員。則派生類的聲明可以改為:
#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類中繼承的獲得圓心坐標的函數(shù)(GetX()和GetY())訪問控制屬性是保護的,派生類對象不能直接訪問,所以在新增成員除了需要添加獲得半徑的函數(shù)GetR(),還需要添加獲得圓心坐標的函數(shù)(GetX()和GetY())。
4)私有繼承和保護繼承的區(qū)別
從類圖上看,類保護繼承和私有繼承似乎一樣:基類私有成員在派生類中不能直接訪問,基類的公有成員和保護成員可以被派生類新增成員訪問,外部使用者不能通過對象直接調(diào)用基類它們。但是,當以派生類作為新的基類繼續(xù)派生的時候,二者的區(qū)別就出現(xiàn)了。
假設(shè)Point類分別以私有和保護兩種繼承方式派生出Circle類,再在Circle類的基礎(chǔ)上以公共繼承的方式派生出圓柱體類Cylin der。仔細分析兩種條件下的圓柱Cylinder類的成員,我們會發(fā)現(xiàn)Point類的公共成員在Cylinder類中訪問控制屬性不同。
//Cylinder.h
#include”Circle.h”
class Cylinder: public Circle
{
private:float h;
public:float GetH() {return h;}
};
參考文獻:
[1]侯俊杰.深入淺出MFC[M].武漢:華中科技大學(xué)出版社,2003.
[2]錢能.C++程序設(shè)計教程[M].北京:清華大學(xué)出版社,1999.
[3]鄭莉,董淵.C++語言程序設(shè)計[M].北京:清華大學(xué)出版社,2001.
[4]薩師煊,王珊.數(shù)據(jù)庫系統(tǒng)概述[M].3版.北京:高等教育出版社,2002.
[5] Date C J.數(shù)據(jù)庫系統(tǒng)導(dǎo)論[M].7版.北京:機械工業(yè)出版社,2000,10.