C++ 筆記 | 第5課 類的繼承與派生

C++ 筆記 | 第5課 類的繼承與派生

繼承和派生

繼承與派生 (Derivation and Inheritance) 是 C++ 的重要機制,是面向對象程序設計的重要特徵。該機制自動爲一個類提供來自另一個類的數據結構和操作。這樣可以利用已構造好的類生成新類,充分利用已有資源,進行代碼複用(code reused)。在構造新類的過程中保持已有類的特性稱爲繼承。在已有類的基礎上新增自己的特性而構造新類的過程稱爲派生

// 如
class Rectangle: public Shape {...};

訪問控制

繼承性質 基類中成員 (函數) 的訪問權限 派生類中成員 (函數) 的訪問權限
public
public
protected
private
public
protected
private
protected
public
protected
private
protected
protected
private
private
public
protected
private
private
private
private

保護成員

對於建立它的類,它與 private 成員的性質相似; 對於繼承此類建立的類,它與 public 成員性質相似

友元與繼承

由於派生類不能直接訪問基類中的私有成員,所以若一個派生類要直接訪問基類中的私有成員,可以將這個派生類聲明爲基類的友元

訪問權限調整

只能恢復原狀, 不能調整訪問權限

public:
Myclass::f; // 恢復 f 的公有屬性
Myclass::g; // 恢復 g 的公有屬性

成員名限定

在派生類和基類中可以聲明同名的成員(函數),不特別說明,在派生類中訪問時,編譯器會默認爲是派生類中的(後出現的),除非用 基類名:: 基類成員名 進行成員名限定,才能調用同名的基類成員(函數)

派生類構造函數與複製構造函數

// 若 B 是基類,A 是派生類,則派生類 A 的構造函數的書寫格式爲: 
A::A(參數表): B(參數){...} // 先構造基類無名對象 B

// 派生類 A 的複製構造函數的書寫格式爲:
A::A(const A &p): B(p){...} // 這裏 B 的參數爲 A 類對象 p,
// 用對象 p 中基類部分去複製構造無名基類對象 B

帶基類內嵌對象的派生類

若有類 Point,私有成員爲 x_, y_ 若要以 Point 作爲基類,生成派生類 LineLine 中希望有兩個 Point 對象 (用兩個點來表示平面座標上的一條直線),若想派生兩次 Point 是不允許的. 在 Line 類中加一個 private 成員 Point p; 就行了(另法:Line 類不繼承 Point 類, 私有成員爲兩個 Point, 函數重新寫(因爲沒有繼承))

動態束定與虛函數

virtual 所修飾的成員函數,被稱爲虛函數。
延遲到程序運行時進行的束定稱爲動態束定 (動態綁定)。

當一個類是從一個或多個類派生出來時,往往會出現多個函數名相同且參數個數和參數類型也完全相同的成員函數,分別實現不同的功能。但這些函數不是重載函數(重載函數必須參數個數或參數類型不同,可以靜態束定),編譯器無法在編譯時靜態束定到底是要調用哪一個成員函數,即使可以靜態束定,往往也不一定符合編程者的真正意願而導致結果錯誤

虛函數延遲到程序運行時再進行動態束定,由 this 指針決定調用 (通過虛函數表(vtable)) 哪一個同名的成員函數
需要在重名的成員函數前加上 virtual 聲明
包含虛函數的類被稱爲多態類
多態性 (polymorphism) 是面向對象的重要特徵之一

類型兼容性規則: 基類指針可以指向它的派生類對象, 反之錯誤。

在派生類中重定義虛函數時,必須滿足:
1 與基類的虛函數參數個數相同;
2 與基類的虛函數參數一一對應;
3 函數返回類型或修飾詞 (如 const) 與基類的虛函數相同,或都返回指針或引用(可以不同類型)。
若滿足上述三條件,有時可以省略 virtual 關鍵字, 編譯器會自動認爲是同族虛函數。
但從程序可讀性角度考慮,建議保留 virtual 關鍵字

純虛函數

純虛函數是抽象類中的虛函數,在函數名後直接賦值爲 0, 無函數體。
純虛函數不同於空函數,是抽象的。
純虛函數爲抽象類中的成員函數。
包含純虛函數的類被稱爲抽象類。
抽象類 (無論類中是否有數據成員) 無法實例化,因此不能用抽象類定義對象。

純虛函數聲明格式:
virtual 函數類型 函數名(參數表)=0;

class Figure{ // Figure 是一個抽象類 
public:
virtual double getArea()=0;// 純虛函數,爲整個類族提供了通用的外部接口語義}; 

虛析構函數

Figure 類中加入虛析構函數 virtual ~Figure(){}~Figure() ~Rectangle() ~Triangle() 變爲同族的虛析構函數。
虛析構函數是 C++ 中唯一的函數名不同的虛函數族。

注意: 有虛析構函數,但沒有對應的虛構造函數。

虛析構函數使系統在執行過程中進行析構時,根據 this 指針所指的當前對象,動態決定使用這個對象的析構函數進行正確析構。(否則都掉用基類的析構函數無法執行派生類自己的析構函數導致析構不徹底)

多繼承

class D : public A, protected B, private C
{...}

多繼承的二義性

若出現二義性 (ambiguous) 則需要在相應成員或成員函數前加基類名限定(如 A::)

虛基類

D 繼承 B 和 C, B 和 C 同時繼承 A, 那麼 D 中會有兩個 A 基類的副本(大多情況下不希望這樣)
C++ 引入了虛基類(virtual base class), 虛基類將使得派生類 D 在繼承間接共同基類 A 時只保留一個 A 的副本。

class A
{...};
class B: virtual public A
{...};
class C: virtual public A
{...};
class D: public B, public C
{...};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章