5.C++子類繼承父類後子類的大小
#include <iostream>
using namespace std;
class A
{
private:
int a;
};
class B:public A
{
private:
int b;
};
int main()
{
cout<<sizeof(A)<<endl;
cout<<sizeof(B)<<endl;
return 0;
}
剛開始我一想子類繼承父類不會繼承父類的私有變量,如此我認爲結果爲4,4(錯誤)。而事實上結果是4,8。也就是說子類把父類的私有變量也繼承下來了,但是卻無法訪問,對於我這種菜鳥來說一下子沒法轉個彎來,後來看看資料煥然大悟,子類雖然無法直接訪問父類的私有變量,但是子類繼承的父類的函數卻可以訪問,不然的話如果只繼承函數而不繼承變量,哪麼父類的函數豈不成了無米之炊了。所以必須把父類的所有變量都繼承下來,這樣既能保護父類的變量也能使用父類的函數。
4.多繼承的構造順序
構造對象的規則需要擴展以控制多重繼承。構造函數按下列順序被調用:
- 任何虛擬基類的構造函數按照它們被繼承的順序構造;
- 任何非虛擬基類的構造函數按照它們被繼承的順序構造;
- 任何成員對象的構造函數按照它們聲明的順序調用;
- 類自己的構造函數。
一個有意思的問題:爲什麼析構函數要設置成虛函數
Range *r1 = new Circle(3, 4);
如果析構函數不是虛函數,則r1在釋放內存時,則調用提Range的析構函數。
結果並不是想要的結果,我們想要的結果是調到Circle對象的析構函數。
如果析構函數是虛函數,有多態的支持,r1調用Circle對象的析構函數,Circle對象的析構函數默認調用父類Range的析構函數,保證Circle和Range對象的內容都得到清除。
4.c++重載、覆蓋、隱藏的區別和執行方式
既然說到了繼承的問題,那麼不妨討論一下經常提到的重載,覆蓋和隱藏
4.1成員函數被重載的特徵
(1)相同的範圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;
(4)virtual 關鍵字可有可無。
4.2“覆蓋”是指派生類函數覆蓋基類函數,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函數名字相同;
(3)參數相同;
(4)基類函數必須有virtual 關鍵字。
4.3“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,特徵是:
(1)如果派生類的函數與基類的函數同名,但是參數不同,此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,但是參數相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。
小結:說白了就是如果派生類和基類的函數名和參數都相同,屬於覆蓋,這是可以理解的吧,完全一樣當然要覆蓋了;如果只是函數名相同,參數並不相同,則屬於隱藏。
重載:函數名相同,函數的參數個數、參數類型或參數順序三者中必須至少有一種不同。函數返回值的類型可以相同,也可以不相同。發生在一個類內部。
重定義:也叫做隱藏,子類重新定義父類中有相同名稱的非虛函數 ( 參數列表可以不同 ) ,指派生類的函數屏蔽了與其同名的基類函數。可以理解成發生在繼承中的重載。
重寫:也叫做覆蓋,一般發生在子類和父類繼承關係之間。子類重新定義父類中有相同名稱和參數的虛函數。(override)
令人迷惑的隱藏規則
本來僅僅區別重載與重寫並不算困難,但是C++的隱藏規則(遮蔽現象)使問題複雜性陡然增加。這裏“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏。
(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual關鍵字。此時,基類的函數被隱藏。
這種隱藏規則,不僅僅是表現在對成員函數上,對同名的data member也是如此。
4.4 三種情況怎麼執行:
4.4.1 重載:看參數。
4.4.2 隱藏:用什麼就調用什麼。
4.4.3 覆蓋:調用派生類。