定不定義
普通成員函數只要沒用到可以不寫定義,但虛函數只要在主函數被用到,所有父類和子類必須都定義該函數,因爲編譯器只有在運行時才能確定用到哪個函數。
調用虛函數
指針或引用運行時解析
有兩種類型:動態和靜態。
這裏有動態類型和靜態類型,只有在運行時才知道動態類型。
Quote base;
print_total(cout, base, 10); //調用Quote::net_price()
Bulk_quote derived;
print_total(cout, derived, 10); //調用Bulk_quote::net_price()
普通類型編譯時解析
只有一種類型:只有靜態了。
如果我們通過普通類型調用虛函數,就只會調用靜態類型的函數。
base = derived; //動態和靜態類型一致
base.net_price(20); //調用Quote::net_price
調用普通函數
測試都是調用基類的函數。
虛函數重寫叫覆蓋,普通函數重寫叫隱藏。
class Base
{
public:
void f()
{
cout<<"Base"<<endl;
}
};
class Derived: public Base
{
public:
void f() //報隱藏非虛函數
{
cout<<"Derived_f"<<endl;
}
void g()
{
cout<<"Derived_g"<<endl;
}
};
int main() {
Base base;
Derived derived;
Base *p = &base;
p ->f(); //輸出Base
p ->g(); //xxx ,報class Base無此函數
p = &derived;
p ->f(); //輸出Base
p ->g(); //xxx ,報class Base無此函數
return 0;
}
口訣-Primer537
普通函數普通類型靜態時,虛函數指針或引用運行時,普通類型還是靜態時。
只有虛函數和引用或指針這倆條件都滿足,纔會動態綁定。
關鍵字
virtual關鍵字的範圍
只要聲明爲virtual,派生類就不用聲明瞭。
虛函數叫覆蓋,形參和返回值都要完全匹配。
override關鍵字
動機
有時我們寫了相同名字的函數,但形參列表和想覆蓋的虛函數不同,這時編譯器視爲新函數,但是其實是想覆蓋,這是一個不小心的錯誤。可以加上override來幫助檢查。
final關鍵字
既可以不讓類繼承,也可以不讓函數覆蓋
忽略虛函數機制
加上作用域就行。