繼承
定義:被繼承的類叫做基類(父類),繼承的類叫派生類(子類),在派生類類名后面加
: 繼承方式 基類
class CFather{};
class CSon:public CFather{};
父類(基類)與子類(派生類)之間的關系:
把一些功能相似的類,類中公共的成員單獨抽離出來,放到一個類中,這個類就是父類
子類如何使用父類對象?:
通過繼承關系,子類可以使用父類的成員。如果子類和父類有同名的成員,默認使用子類的成員,如果想要使用父類的成員,需要在成員名前加上類名::用于顯式的指定區分,
son.m_a; //子類成員
son.CSon::m_a; //子類成員
son.CFather::m_a; //父類成員
?子類繼承父類,相當于將父類的成員包含到自己的類里,所以定義子類對象所占用的空間大小除了子類自身的成員還包括父類的成員。成員在內存空間分布為:先父類成員后子類成員,而每個類中的成員分布與在類中聲明的順序一致。
?
?三種繼承方式:
繼承方式與訪問修飾符一樣,都是三種
繼承方式:描述了父類的成員在子類中所能使用的范圍,即訪問控制。繼承方式和訪問修飾符共同決定了父類成員的訪問權限。
繼承格式:
class 子類名:繼承方式 父類名
class CSonson :public CSon{};
?
父類 | 子類 |
private: | 不可訪問 |
protected: | private: |
public: | private: |
父類 | 子類 |
private: | 不可訪問 |
protected: | protected: |
public: | protected: |
父類 | 子類 |
private: | 不可訪問 |
protected: | protected: |
public: | public: |
繼承下構造析構執行的順序:
定義子類對象時執行順序:父構造->子構造->孫構造...| ...孫析構->子析構->父析構。
?構造順序說明:
在子類創建對象的時候,執行子類的構造函數(注意這里并不是直接先執行父類的構造函數),但要先執行子類的構造的初始化列表,在初始化列表中會默認調用父類的無參構造初始化父類成員,如果父類只有帶參數的構造,那么需要在子類的初始化參數列表顯示的指定父類的初始化。
析構順序說明:
子類對象的生命周期結束后,因為是子類所以自動調用子類析構,當析構執行完了,才會回收對象分配的空間,當然這個空間包含創建的父類的成員,那么回收父類成員前,自動調用父類的析構。如果是new出來的子類對象,同理。?
?繼承的優點:
多個子類在增加公共方法時,只需要在父類添加一份即可,提高了代碼的復用性,擴展性。
?隱藏
定義
隱藏:在繼承的條件下,父類和子類中有同名的成員,那他們之間的關系稱為隱藏。
如果子類中沒有函數,則他會調用父類的函數,但當調用父類和子類的同名成員方法時,他會調用子類中的函數,將傳輸的參數轉換成子類中的函數所需類型,如果轉換不了則會報錯。父類和子類中,同名的但是參數列表不同的函數,他們之間的關系并不是函數重載的關系,作用域不同,必須使用 類名:: 去區分到底該調用哪個函數。
class CFather {void fun();
};
class CSon :public CFather {void fun(int a); //隱藏關系,自動將父類的成員屏蔽了
};
?注:父類指針不強轉,也可以指向子類對象;而子類的指針必須通過強轉才能指向父
親對象。
?父類指針指向子類對象
CFather * p = new CSon;
?優點:統一多種子類類型,提高代碼的復用性和擴展性
弊端:只能使用父類的成員,不能使用子類的成員