Virtual是C++ OO機制中很重要的一個關鍵字。只要是學過C++的人都知道在類Base中加了Virtual關鍵字的函數就是虛擬函數(例如函數print),於是在Base的派生類Derived中就可以通過重寫虛擬函數來實現對基類虛擬函數的覆蓋。當基類Base的指針point指向派生類Derived的對象時,對point的print函數的調用實際上是調用了Derived的print函數而不是Base的print函數。這是面向對象中的多態性的體現。(關於虛擬機制是如何實現的,參見Inside the C++ Object Model ,Addison Wesley 1996)
class Base { public:Base(){} public: virtual void print(){cout<<"Base";} }; class Derived:public Base { public:Derived(){} public: void print(){cout<<"Derived";} }; int main() { Base *point=new Derived(); point->print(); }
Output:
Derived
這也許會使人聯想到函數的重載,但稍加對比就會發現兩者是完全不同的:
(1) 重載的幾個函數必須在同一個類中;
覆蓋的函數必須在有繼承關系的不同的類中
(2) 覆蓋的幾個函數必須函數名、參數、返回值都相同;
重載的函數必須函數名相同,參數不同。參數不同的目的就是為了在函數調用的時候編譯器能夠通過參數來判斷程序是在調用的哪個函數。這也就很自然地解釋了為什么函數不能通過返回值不同來重載,因為程序在調用函數時很有可能不關心返回值,編譯器就無法從代碼中看出程序在調用的是哪個函數了。
(3) 覆蓋的函數前必須加關鍵字Virtual;
重載和Virtual沒有任何瓜葛,加不加都不影響重載的運作。
關於C++的隱藏規則:
我曾經聽說過C++的隱藏規則:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual
關鍵字,基類的函數將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual
關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆)。