雖然寫過一些C++程式,有類有繼承,但對虛函數和多態用的不多,最近想嘗試一下多態,卻出了些問題。於是不得不重新來學習虛函數與多態。
簡單的樣本程式如下,
class Lexer{public: Lexer(){} Lexer(string t){ name = "Lexer"; text = t; } virtual void Print(){ cout << name << ":" << text << endl; }protected: string name; string text;};class ExprLexer : public Lexer{public: ExprLexer(){} ExprLexer(string t,string r):Lexer(t){ name = "ExprLexer"; expr = r; } void Print(){ cout << name << ":" << text << "," << expr << endl; }protected: string expr;};class Parser{public: Parser(Lexer l){ lexer = l; // lexer = &l; //雖然這樣修改,但結果沒什麼變化 } void Print(){ lexer.Print(); // lexer->Print(); }protected: Lexer lexer; // Lexer *lexer;};
輸出結果如下,
輸出結果卻不是我所期望的,多態和虛函數為什麼沒有作用呢?我在《C++程式設計語言(特別版)》的278頁找到了答案。
“從Employee的函數中取的'正確的'行為,而又不依賴於實際使用的到底是哪一種Employee,這就是所謂的多態性。一個帶有虛函數的類型被稱為多態類型。要在C++裡取的多態的行為,被調用的函數就必須是虛函數,而對象則必須是通過指標或者引用去操作的。如果直接操作一個對象(而不是通過指標或引用),它的確切類型就已經為編譯器所知,因此也就不需要運行時的多態性了。”
讀完這段話,如醍醐灌頂,發現自己根本就不會用多態和虛函數。C++白學了這麼多年啊。下面對Parser類做些簡單的修改,就可以了,修改之後的代碼如下,
class Parser{public: Parser(Lexer* l){ lexer = l; } void Print(){ lexer->Print(); }protected: Lexer *lexer;};
主程式也需要稍作修改,如下,
int main(){ Lexer A("hello,A"); ExprLexer B("hello,B","1+1=2"); A.Print(); B.Print(); Parser C(&A); C.Print(); Parser D(&B); D.Print(); return 0;}
得到輸出,
總算得到期望的結果了。多態和虛函數還是蠻好用的哈。