1. 程式人生 > >C++類物件中虛擬函式與多型性的實現

C++類物件中虛擬函式與多型性的實現

在面向物件程式設計時,有時會遇到這種需求:我們希望同一個方法在基類和派生類中實現不同的功能,即體現出行為上的多型性。一般有兩種方法可以實現這種需求,其一是在派生類中重新定義基類中方法,其二是使用虛擬函式。這裡主要記錄利用虛擬函式實現多型性的方法。

類中虛擬函式的定義方法

虛擬函式使用關鍵詞virtual進行標識。通過一個例子加深對虛擬函式的理解,一個銀行需要開發兩類賬戶,一類是基本賬戶BaseAcct,另一類是高階賬戶PlusAcct,具有透支功能,多顯示透支上限和透支額度資訊。兩個賬戶的基本特徵為:

class BaseAcct{
	private:
	    string fullName;
long balance; public: BaseAcct(const stirng &s="Nullbody", long bal=0.0); void Deposit(double amt); //存款 virtual void Withdraw(double amt); //取款,無透支功能 virtual void ViewAcct() const; virtual ~BaseAcct() {}; //基類解構函式最好定義為虛擬函式以保證正確的析構順序 };
class PlusAcct:public BaseAcct{
private: double maxLoan; //透支上限和透支額度 double owesBank; public: PlusAcct(const stirng &s="Nullbody", long bal=0.0, double ml=500, double ob=0.0); virtual void Withdraw(double amt); //取款,有透支功能 virtual void ViewAcct() const; //多顯示透支上限和透支額度 ~PlusAcct() {}; //解構函式是自帶預設的,可以不寫 };

派生類PlusAcct中對基類BaseAcct中的虛擬函式Withdraw()和ViewAcct()進行改寫,實現了不同的功能。可以在後續進行重寫,這是虛擬函式的特點。但是重寫時要注意,重寫的函式其函式原型要保持與基類中完全相同,否則編譯器將會產生warning。只有返回值可以由基類指標/引用改變為派生類指標/引用,稱之為返回值協變。

上述特點與過載不同,過載中要求函式的引數列表必須不同才能實現過載。

虛擬函式的工作原理

編譯器在處理虛擬函式的方法是為每一個物件增加一個隱藏成員,其中儲存了一組指向虛擬函式陣列地址的指標,一般稱之為虛擬函式表。

動態聯編與多型性

在管理BaseAcct和PlusAcct帳戶時,不能用一個數組去儲存BaseAcct和PlusAcct物件,因為兩者的型別不同。但是卻可以建立指向BaseAcct類的指標陣列,然後根據需要讓其指向BaseAcct或PlusAcct物件。因為編譯器在處理虛擬函式時是採用動態聯編的,即在程式執行的時候再選擇正確的虛方法。而這種動態聯編的特性,可以讓同一個陣列中的指標指向不同的基類或者派生類,並讓其表現出不同的特性,即為多型性。

通過指標或者引用呼叫方法時,若為virtual,將根據指標或者引用指向物件選擇方法;若非virtual,將根據指標或者引用本身的型別選擇方法。這個特性是類物件實現多型性的基礎。

祝楓
2018年10月9日