面對物件程式設計
繼承是為了解決**的復用性
1.怎麼解決**的復用性?
組合和繼承
組合:將乙個類作為另乙個類的物件成員。
繼承:class a
}class b
private:
a a_;
}
使用已有的類來建立新的類,新的類具有原有類的所有屬性和操作,也可以增加新的屬性和方法。
原有的類稱為基類或者父類,新的類稱為派生類或者子類
派生類是基類的具體化。
派生類的語法宣告:
class 派生類名:繼承方式 基類名
二、繼承規則
派生類三種繼承方式:公有繼承、私有繼承、保護繼承
公有繼承:父類成員在子類中保持原有的訪問級別。
私有繼承:父類成員在子類中變為private成員。
保護繼承:父類成員在子類中變為protected成員。
2、預設繼承的保護級別:
class base{};
struct d1:base{};//公有繼承
class d2:base{};//私有繼承
3、不能自動繼承的成員函式
(a)建構函式、析構函式、賦值運算子
(1)建構函式
派生類不能訪問基類的私有成員,必須通過基類的方法來訪問。
派生類建構函式必須使用基類建構函式。
派生類通過初始化列表來呼叫基類建構函式。
基類、派生類、子物件呼叫順序。
子物件: 駐留在另乙個物件中的物件,在乙個類的定義中,宣告另乙個類的物件來作為成員變數。
建構函式:基類子物件–基類–派生類子物件–派生類
細狗函式:相反
(2)析構函式
(3)賦值運算子(operator=)
解釋原因:
編譯器總是根據型別來呼叫類成員函式。
但是乙個派生類的指標可以安全地轉化為乙個基類的指標。這樣刪除乙個基類的指標的時候,c++不管這個指標指向乙個基類物件還是乙個派生類的物件,呼叫的都是基類的析構函式而不是派生類的。如果你依賴於派生類的析構函式的**來釋放資源,而沒有過載析構函式,那麼會有資源洩漏。所以建議的方式是將析構函式宣告為虛函式。
也就是delete a的時候,也會執行派生類的析構函式。
乙個函式一旦宣告為虛函式,那麼不管你是否加上virtual 修飾符,它在所有派生類中都成為虛函式。但是由於理解明確起見,建議的方式還是加上virtual 修飾符。
構造方法用來初始化類的物件,與父類的其它成員不同,它不能被子類繼承(子類可以繼承父類所有的成員變數和成員方法,但不繼承父類的構造方法)。因此,在建立子類物件時,為了初始化從父類繼承來的資料成員,系統需要呼叫其父類的構造方法。
如果沒有顯式的建構函式,編譯器會給乙個預設的建構函式,並且該預設的建構函式僅僅在沒有顯式地宣告建構函式情況下建立。
構造原則如下:
1. 如果子類沒有定義構造方法,則呼叫父類的無引數的構造方法。
2. 如果子類定義了構造方法,不論是無引數還是帶引數,在建立子類的物件的時候,首先執行父類無引數的構造方法,然後執行自己的構造方法。
3. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式,則會呼叫父類的預設無參建構函式。
4. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式且父類自己提供了無參建構函式,則會呼叫父類自己的無參建構函式。
5. 在建立子類物件時候,如果子類的建構函式沒有顯示呼叫父類的建構函式且父類只定義了自己的有參建構函式,則會出錯(如果父類只有有引數的構造方法,則子類必須顯示呼叫此帶參構造方法)。
6. 如果子類呼叫父類帶引數的構造方法,需要用初始化父類成員物件的方式,比如:
執行結果:#include
classanimal
void f1(string a) ;
class derivea:public base
;class deriveb:public base
;int main()
綜上所述,總結如下:
1 成員函式過載特徵:
a 相同的範圍(在同乙個類中)
b 函式名字相同
c 引數不同
d virtual關鍵字可有可無
2 重寫(覆蓋)是指派生類函式覆蓋基類函式,特徵是:
a 不同的範圍,分別位於基類和派生類中
b 函式的名字相同
c 引數相同
d 基類函式必須有virtual關鍵字
3 重定義(隱藏)是指派生類的函式遮蔽了與其同名的基類函式,規則如下:
a 如果派生類的函式和基類的函式同名,但是引數不同,此時,不管有無virtual,基類的函式被隱藏。
b 如果派生類的函式與基類的函式同名,並且引數也相同,但是基類函式沒有vitual關鍵字,此時,基類的函式被隱藏。
注意區分虛函式中的過載和重寫:
class a };
class b:public a
//這是過載而不是重寫:
}int mian()
// 新的fun, 和前面的只是名字一樣的過載函式, 不是虛函式
} (3)組合與繼承
5、基類、派生類之間的轉換
(1)派生類到基類的轉換
1. 公有繼承時,編譯器自動執行轉換,就是向上轉型,
派生類物件指標自動轉換為基類物件指標。
派生類引用自動轉化為基類物件引用。
派生類物件自動轉化為基類物件(特有的成員消失)
2.private/protected繼承
派生類物件指標(引用)轉化為基類物件指標(引用),必須強制型別轉化。使用reinterpret_cast;
不能把派生類物件強制轉化為基類物件。
(2)基類物件指標(引用)可強制型別轉換為派生類物件指標(引用),而基類物件無法執行這類轉換。
向下轉型不安全,沒有自動轉換的機制。
6、多繼承與多重繼承
(1)多繼承
class a;
class b;
class c: public a,public b;
解決二義性的問題(a和b中有相同的成員函式),採用限制域作用符::。
(2)多重繼承(乙個派生類可以有很多基類)
class a;
class b: public a;
class d:public a,public b;
派生類同時繼承多個基類的成員,更好的軟體重用性。
可能會有大量的二義性,多個基類中可能包含同名的變數或函式。
解決方法:
1.基類名::成員名。
2.採用虛基類來解決。
7、虛基類、虛繼承
(1)虛基類的語法宣告:class b1 : virtual public bb;
(2)虛基類的作用:解決多重繼承的二義性問題
為最遠的派生類提供唯一的基類成語,而不重複產生多次拷貝。
(3)建構函式的問題
1.虛基類的成員是由最遠派生類的建構函式通過呼叫來實現初始化的。
2.在整個繼承結構中,直接或間接繼承虛基類的所有派生類,都必須在建構函式的成員初始化表中給出對虛基類的建構函式的呼叫
3.建立物件時,只有最派生類的構造函式呼叫虛基類的建構函式,該派生類的其他基類對虛基類建構函式的呼叫被忽略
8、虛繼承對c++物件記憶體模型造成的影響。
深入理解C 之繼承
目錄 繼承 封裝和多型是物件導向程式設計的重要特性。其成員被繼承的類叫基類也稱父類,繼承其成員的類叫派生類也稱子類。派生類隱式獲得基類的除建構函式和析構函式以外的所有成員。派生類只能有乙個直接基類,所以c 並不支援多重繼承,但乙個基類可以有多個直接派生類。繼承是可以傳遞的。即 如果classb派生出...
對C 繼承的理解
繼承是一種 復用的方式,使得我們不必寫重複的 例如,有三種怪物a b c,他們都有速度 血量 攻擊力 防禦值 攻擊方式。如果沒有繼承我們可能要寫三個指令碼monstera monsterb monsterc,而且在某個指令碼中我們還要重複的宣告定義變數speed等。如果這有三種怪物,那麼貼上複製起來...
對C 繼承的理解
繼承是可用傳遞的 子類是對父類的擴充套件 必須繼承父類的方法,同時在子類中新增新方法。子類可用呼叫父類的公用方法和字段 而父類不能呼叫子類的成員。子類不僅繼承了父類的共有成員 同時也繼承了父類的私有成員 只是在子類中不能被訪問。繼承的三個關鍵字 abstract 抽象。用來限定類時,類中的方法不能有...