C++繼承詳解

公有繼承(public)、私有繼承(private)、保護繼承(protected)是常用的三種繼承方式。

1. 公有繼承(public)

公有繼承的特點是基類的公有成員和保護成員作爲派生類的成員時,它們都保持原有的狀態,而基類的私有成員仍然是私有的,不能被這個派生類的子類所訪問。

2. 私有繼承(private)

私有繼承的特點是基類的公有成員和保護成員都作爲派生類的私有成員,並且不能被這個派生類的子類所訪問。

3. 保護繼承(protected)

保護繼承的特點是基類的所有公有成員和保護成員都成爲派生類的保護成員,並且只能被它的派生類成員函數或友元訪問,基類的私有成員仍然是私有的。

下面列出三種不同的繼承方式的基類特性和派生類特性。

  public protected private
共有繼承 public protected 不可見
私有繼承 private private 不可見
保護繼承 protected protected 不可見

在上圖中:1)基類成員對派生類都是:共有和保護的成員是可見的,私有的的成員是不可見的。

                  2)基類成員對派生類的對象來說:要看基類的成員在派生類中變成了什麼類型的成員。如:私有繼承時,基類的共有成員和私有成員都變成了派生類中的私有成員,因此對於派生類中的對象來說基類的共有成員和私有成員就是不可見的。

 爲了進一步理解三種不同的繼承方式在其成員的可見性方面的區別,下面從三種不同角度進行討論。

對於公有繼承方式

(1) 基類成員對其對象的可見性:

公有成員可見,其他不可見。這裏保護成員同於私有成員。

(2) 基類成員對派生類的可見性:

公有成員和保護成員可見,而私有成員不可見。這裏保護成員同於公有成員。

(3) 基類成員對派生類對象的可見性:

公有成員可見,其他成員不可見。

所以,在公有繼承時,派生類的對象可以訪問基類中的公有成員;派生類的成員函數可以訪問基類中的公有成員和保護成員。這裏,一定要區分清楚派生類的對象和派生類中的成員函數對基類的訪問是不同的。

對於私有繼承方式

(1) 基類成員對其對象的可見性:

公有成員可見,其他成員不可見。

(2) 基類成員對派生類的可見性:

公有成員和保護成員是可見的,而私有成員是不可見的。

(3) 基類成員對派生類對象的可見性:

所有成員都是不可見的。

所以,在私有繼承時,基類的成員只能由直接派生類訪問,而無法再往下繼承。

對於保護繼承方式

這種繼承方式與私有繼承方式的情況相同。兩者的區別僅在於對派生類的成員而言,對基類成員有不同的可見性。

上述所說的可見性也就是可訪問性。

關於可訪問性還有另的一種說法。這種規則中,稱派生類的對象對基類訪問爲水平訪問,稱派生類的派生類對基類的訪問爲垂直訪問。


=========================================================

詳細講解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的友元,即友元關係也不具有傳遞性。

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


發佈了1 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章