C++繼承與組合
繼承與組合
繼承和組合這兩種方式得到的對象的內存結構是完全相同的,但是使用組合時要重寫所包含類對象的部分成員函數
例如:
當使用組合時,要獲取成員對象時如果不重寫成員函數,就需要用
m_Cperson.GetSex()和m_Cperson.GetName來獲取成員對象的信息
繼承方式和訪問控制
注:
- 上述表格中的"不可見"只是編譯時檢查是否有代碼訪問父類中的私有成員,無論以何種方式繼承,父類中的
私有數據成員和成員函數在子類中均是不可見的,繼承方式是 用來重新指定父類的成員在子類中的訪問權限。 - 如果在繼承時沒有指明繼承的方式,默認的是私有繼承
- 如果父類中有修改私有數據成員的非私有成員函數,那么在子類中調用調用父類的這些成員函數是可以改變
父類的私有數據成員的。 - 當創建子類對象時,是先創建繼承的父類的對象,父類對象放在最前面,這樣做一是為了兼容性考慮,
如果以后子類要進行成員擴充,只需要在尾部添加即可,先前的程序不用做改動依舊可以正常訪問,這樣做
也有簡化了編譯器計算父類對象的偏移。 - 數據隱藏和函數重載的區別:
數據隱藏:a.不同作用域 b.成員名稱相同 c.參數列表相同
函數重載:a.作用域相同 b.函數名稱相同 c.參數列表不同
繼承時成員函數的訪問方式:
- 當寫有子類對象調用函數的代碼時,編譯器先在子類的類域中尋找是否有該名稱的函數,如果有這樣的一個
或者多個函數名稱挑,就選出最佳的 (這個過程與調用重載函數類似),如果有該名稱的函數,但是參數列表
不匹配,這時就會報錯,即使所繼承的父類中有匹配的同名函數,編譯器也不會在父類的類域中尋找. - 當寫有子類對象調用函數的代碼時,編譯器先在子類的類域中尋找是否有該名稱的函 數,如果子類的類域中
沒有該名稱的函數,那么編譯器就去父類的類域中尋找是否有匹配的該名稱函數,如果沒有就報錯 - 當子類和父類中有同名的函數時,當調用該函數時,默認的是優先調用子類的同名函數,其過程如上述第一
項所描述,如果要想調用父類的同名函數,只能在調用時在函數名前加上父類的類域
子類對象向父類對象的類型轉換:
一個子類對象包含兩大部分:子類自己定義的成員和繼承的其它父類對象(當然可能還有組合對象),因為子類對
象中含有基類的部分,所以可以把子類對象當成父類對象來使用,還可以將指向父類對象的指針指向子類中的
父類部分。
例如:
CStudent * pstu = new CStudent(“xx”,’f’,7); CPerson * pPer = pstu; pPer->GetSex();
但是讓一個指向子類對象的指針指向父類的對象,是不安全的,可能會發生越界訪問造成程序異常,除非可以
確定該父類對象是被包含在子類對象中。
繼承時的構造和析構順序:
- 構造:先構造父類對象,並且只能在子類構造函數的初始化列表中調用父類的構造函數來初始化父類對象部
分,在構造子類自己的數據成員 - 析構:先析構子類的,在析構父類的,因為子類中可能使用了父類的資源
繼承與組合同時使用時的構造和析構順序:
構造時先調用父類的構造函數,在調用成員對象的構造函數,最后調用自己的構造函數,析構時先析構自己,
在調用成員對象的析構函數,最后調用父類的析構函數。