多態原理
當類存在虛函數時,編譯器會為該類維護一個表,這個表就是虛函數表(vtbl),里面存放了該類虛函數的函數指針。在構造類的時候增加一個虛表指針(vptr)指向對應的虛函數表。在類執行成員函數時候,先判斷該函數是否是虛函數,如果不是虛函數則直接執行對應的方法,如果是虛函數則從虛函數表中找到應該調用的函數。
- vptr的初始化是在類的構造時候完成。而在進行父類構造的時候,vptr指向的是父類vtbl。執行完子類的構造函數后,vptr在指向子類的btbl。
- 父類指針(引用)指向子類進行多態調用時候,編譯器并不關系是子類還是父類,而是通過vptr指向的btbl來找到對應的函數指針,并調用函數。
- vtbl由編譯器來維護
重載、覆蓋、隱藏的區別和執行方式
4.1成員函數被重載的特征
(1)相同的范圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;
(4)virtual 關鍵字可有可無。
4.2“覆蓋”是指派生類函數覆蓋基類函數,特征是:
(1)不同的范圍(分別位于派生類與基類);
(2)函數名字相同;
(3)參數相同;
(4)基類函數必須有virtual 關鍵字。
4.3“隱藏”是指派生類的函數屏蔽了與其同名的基類函數,特征是:
(1)如果派生類的函數與基類的函數同名,但是參數不同,此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,但是參數相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。
小結:說白了就是如果派生類和基類的函數名和參數都相同,屬于覆蓋,這是可以理解的吧,完全一樣當然要覆蓋了;如果只是函數名相同,參數并不相同,則屬于隱藏。
示例
class Parent {
public:
int x;
Parent(int x) {
this->x = x;
}
void print() {
cout << "Parent " << x << endl;
}
};
class Children : public Parent {
public:
Children(int x) : Parent(x) {
}
void print() {
cout << "Children " << x << endl;
}
};
int main() {
Parent *parent = NULL;
Parent p(1);
Children c(10);
parent = &p;
parent->print();
parent = &c;
parent->print();
}
測試一運行結果,發現雖然父類指針或引用指向了子類,但是在調用方法時候還是調用的父類的方法
Parent 1
Parent 10
測試二,對print方法加上virtual關鍵字,這時才體現出多態
Parent 1
Children 10