1. 程式人生 > >詳細講解C++ 類的繼承

詳細講解C++ 類的繼承

一個私有的或保護的派生類不是子類,因為非公共的派生類不能做基類能做的所有的事,就是指在公開場合,但是在類內部可以的

一、引言

在C++中,類是提供封裝的邏輯單位,類的每一個物件都包含有描述其自身狀態的資料集合,並且通過接收特定的訊息來處理這個資料集合。如果程式設計人員能夠通過增加、修改或替換指定類的部分內容的方法對該類進行剪裁,就可以適應不同的應用,從而在很大程度上增強了資料封裝的價值,而接下來要討論的繼承就完全可以實現這種操作。

二、與繼承有關的基本概念

繼承是一個程序,通過繼承,一個物件可以獲得另一個物件的屬性(包括函式),並可向其中加入屬於自己的一些特徵。作為C++語言的一種重要機制,用繼承的方法可以自動為一個類提供來自另一個類的操作和資料結構,進而使程式設計人員在一個一般的類的基礎上很快建立一個新的類,而不必從零開始設計每個類。

當一個類被其他的類繼承時,被繼承的類稱為基類(可不是雞肋^_^),又稱為父類。

繼承其他類屬性的類稱為派生類,又稱為子類。

一般情況下,繼承的程序起源於一個基類的定義,基類定義了其所有派生類的公有屬性。從本質上講,基類具有同一類集合中的公共屬性,派生類繼承了這些屬性,並且增加了自己特有的屬性。從任何已存在的類繼承的實質就是建造新的派生類。

三、單重繼承、多重繼承與繼承鏈

從一個基類派生的繼承稱為單繼承,換句話說,派生類只有一個直接基類。單繼承宣告語句的常用格式為:

class 派生類名: 訪問控制關鍵字 基類名
{
  資料成員和成員函式宣告
};

與此相對地,從多個基類派生的繼承稱為多繼承或多重繼承,也就是說,一個派生類有多個直接基類。在某些面向物件的語言(如Java)中不支援類間的多重繼承而只支援單重繼承,即一個類至多隻能有一個直接父類,因此實現類似的功能需要藉助介面等其他機制。而在C++中提供了多重繼承的語法支援,使得問題變得簡單了許多。多重繼承宣告語句的常用格式為:

class 派生類名: 訪問控制關鍵字 基類名1, 訪問控制關鍵字 基類名2,...
{
  資料成員和成員函式宣告
};

除了多重繼承之外,一個派生類繼承多個基類還有一種方法,就是把派生類作為基類再次供別的類繼承,產生多層次的繼承關係。例如類A派生類B,類B派生類C,則稱類A是類B的直接基類,類B是類C的直接基類,類A是類C的間接基類。類的層次結構也叫做繼承鏈。還是上面的例子,當建立類C的物件時,類A的建構函式最先被呼叫,接下來被呼叫的是類B的建構函式,最後是類C的建構函式。解構函式的呼叫順序正好相反。當一個派生類繼承有層次的類時,繼承鏈上的每個派生類必須將它需要的變數傳遞給它的基類。

四、公有派生和私有派生

在繼承宣告語句中,訪問控制關鍵字用於說明在基類定義中所宣告的成員和成員函式能夠在多大範圍內被派生類所訪問。訪問控制關鍵字可為public, private或protected。如果訪問控制關鍵字為public,則稱派生類從基類公有繼承,也稱公有派生。如果訪問控制關鍵字為private,則稱派生類從基類私有繼承,也稱私有派生。現在筆者將公有繼承和私有繼承的具體區別列表如下。

通過上表,我們可以將兩種派生的特點總結如下:

基類成員 基類private成員 基類public成員
派生方式 private public private public
派生類成員 不可見 不可見 可見 可見
外部函式 不可見 不可見 不可見 可見

(1)無論哪種派生方式,基類中的private成員在派生類中都是不可見的。也就是說,基類中的private成員不允許外部函式或派生類中的任何成員訪問。

(2)public派生與private派生的不同點在於基類中的public成員在派生類中的訪問屬性:
public派生時,基類中的public成員相當於派生類中的public成員。
private派生時, 基類中的public成員相當於派生類中的private成員。

因此,private派生確保基類中的方法只能被派生類的物件的方法間接使用,而不能被外部使用。public派生使派生類物件與外部都可以直接使用基類中的方法,除非這些方法已經被重新定義。

五、保護成員與保護派生

如果想做到基類成員只由有派生血緣關係的成員訪問,而不被無血緣關係的物件成員訪問,無論用公有派生還是私有派生都無法做到。因為基類成員中的私有成員是別的類(包括派生類)成員不能訪問的,而基類中的公有成員在public派生時,不僅可以由派生類物件成員訪問,也可以由外部函式訪問;而在private派生時,基類中的公有成員雖然允許派生類物件中的成員訪問,不允許外部訪問,可是再派生出下一級時,由於基類的所有成員已經被私有化,其它類成員也不可再訪問。實現只許有派生血緣關係的物件成員訪問的方法,是在基類中使用具有另一種訪問屬性的成員——protected成員。

protected成員是一種血緣關係內外有別的成員。它對派生物件而言,是公有成員,可以訪問;對血緣關係外部而言,與私有成員一樣被隱藏。

此外,除了允許使用private與public兩種派生方式之外,C++還允許使用protected派生方式。現在將三種訪問屬性不同的成員經三種派生後在派生類中訪問屬性的變化情況總結如下表,是對上一表格的增進和補充。

派生方式 基類的public成員 基類的protected成員 基類的private成員 派生方式引起的訪問屬性變化概括
private派生 變為private成員 變為private成員 不可見 基類中的非私有成員都成為派生類中的私有成員
protected派生 變為protected成員 變為private成員 不可見 基類中的非私有成員在派生類中的訪問屬性都降一級
public派生 仍為public成員 仍為protected成員 不可見 基類中的非私有成員在派生類中的訪問屬性保持不變

需要注意的是,基類的private成員無論經過何種派生,在派生類中都是不可見的。

六、友元類和友元函式

(1)友元函式

通常,類的私有成員只能由本類的成員訪問,外部函式只能訪問類的成員函式,再由成員函式訪問類的私有成員。但是,如果在某個類定義中用friend聲明瞭一個外部函式(也許是其他類的一個成員)後,這個外部函式便可以例外地訪問該類的任何私有成員。用friend聲明瞭的外部函式稱為這個類的友元函式。

當友元函式是另一個類的成員函式時,應當注意以下幾點:

A:友元函式作為一個類的成員函式時,除應當在它所在的類定義中宣告之外,還應當在另一個類中宣告它的友元關係,宣告語句的格式為:

friend 函式型別 函式所在類名::函式名(引數列表);

B:友元函式在引用本類物件的私有成員時無需本類物件的引用引數,但在引用生命它是友元的類的物件中的私有成員時必須有友元類物件的引用引數。

C:一個類的成員函式作另一個類的友元函式時,必須先定義,而不是僅僅宣告它。

使用友元函式直接訪問物件的私有成員,可以免去再呼叫類的成員函式所需的開銷。同時,友元函式作為類的一個介面,對已經設計好的類,只要增加一條宣告語句,便可以使用外部函式來補充它的功能,或架起不同類物件之間聯絡的橋樑。然而,它同時也破壞了物件封裝與資訊隱藏,使用時需要謹慎小心。

(2)友元類

也可以把一個類而不僅僅是一個函式宣告為另一個類的友元類。這時,只需先宣告它而不一定需要先定義。

應當注意,友元關係是單向的,並且只在兩個類之間有效。即使類X是類Y的友元,類Y是否是類X的友元也要看類X中是否有相應的宣告。即友元關係不具有交換性。若類X是類Y的友元,類Y是類Z的友元,也不一定就說明類X是類Z的友元,即友元關係也不具有傳遞性。

當一個類要和另一個類協同工作時,使一個類成為另一個類的友元類是很有用的。這時友元類中的每一個成員函式都成為了對方的友元函式。