Virtual Function Jing(井民全)
Virtual Function基本概念 基礎類別定義基本的功能 衍生類別 繼承了基礎類別 定義特殊的功能 class Animal weight eat() SetWeight() 動物的基本功能 class Cat eat() SetWeight() Sleep() 貓的功能
Virtual Function基本概念 class Animal class Cat class Animal { public: int weight; void eat(); void setWeight(); }; class Animal weight eat() SetWeight() 動物的基本功能 class Cat:public Animal { public: void eat(); void setWeight(); void Sleep(); }; class Cat eat() SetWeight() Sleep() 貓的功能
Virtual Function基本概念 貓有貓的吃飯方式! class Animal Cat *Mycat=new Cat(); weight eat() SetWeight() 動物的基本功能 Cat *Mycat=new Cat(); Mycat->eat(); class Cat eat() SetWeight() Sleep() 貓的功能
Virtual Function基本概念 ? 因為貓是動物的一種, 所以我們可以用動物reference貓 class Animal Polymorphism(多形) class Animal weight eat() SetWeight() class Cat Sleep() 動物的基本功能 貓的功能 Cat *Mycat=new Cat(); Animal *obj=Mycat; obj->eat(); ?
Virtual Function基本概念 呼叫貓的eat(): 加入 virtual 關鍵字 class Animal class Cat weight eat() virtual SetWeight() class Cat SetWeight() Sleep() 動物的基本功能 貓的功能 Cat *Mycat=new Cat(); Animal *obj=Mycat; obj->eat(); virtual 範例程式: virtualConcept1.cpp
只要是Animal型別就可以操作 可以視為 Animal 型態操作,又可呼叫自己特別function. 泛型處理 Animal 存取未知物件 的相對應的 function 可以視為 Animal 型態操作,又可呼叫自己特別function. 泛型處理
介面的概念 建立一個功能 只接受某種型態的物件 某些電器需要的是三孔插座,某些電器需要的是220V的電壓 電力公司服務 電器1 電器2 我是三孔插座 我是220V 插頭必須是三孔 電壓一定要符合 220V 電器1 電器2
介面的概念 接受電力公司提供服務的條件 擁有三孔插座 可接受 220V 電壓 若想接受服務, 則電器(物件)必須符合條件!! 3孔介面
class TV:public Plug3,public Volate220{ public: void input3(){ } 3孔介面 120V電視機 220V介面 class Plug3{ virtual public void Input3() =0; } class Volate220V{ virtual public void Input220V() =0; class TV:public Plug3,public Volate220{ public: void input3(){ } void input220V(){ }; 把3孔轉2孔的轉換程式放在這 把220轉120V電壓轉換程式放在這
虛擬解構式 範例程式: VirtualDestructor.dsw class Sortable sp=pp; class Person 假設 Person 繼承 Sortable Sortable *sp; Person *pp=new Person("Frank","frank@icce.rug.nl","363 3688"); // 使用基礎類別指標 reference Person sp=pp; 請問下面的程式碼,會呼叫 Sortable 還是 Person 的解構子? delete sp; <解答> 若不加入 virtual 在sp的解構式中,則 delete sp 會呼叫 sp的解構子,而非 Person的解構子
虛擬解構式 所以應該在基礎類別 Sortable 的解構式中加入 virtual. class Sortable{ // < 其他程式碼 > virtual ~Sortable( ){ } 如此 delete sp; 才會呼叫正確的 Person的解構式
Delete Derived 會呼叫 Derived虛擬解構式, 但是程式會繼續呼叫 Base 的解構式嗎? 問題: Delete Derived 會呼叫 Derived虛擬解構式, 但是程式會繼續呼叫 Base 的解構式嗎? 我們知道在 Sortable 的解構子加上 virtual後, 執行delete sp; 會呼叫目前指向物件的解構子 Sortable *sp; Person *pp=new Person("Frank","frank@icce.rug.nl","363 3688"); // 使用基礎類別指標 reference Person sp=pp; delete sp; class Sortable class Person 2. 執行Sortable的解構子 1. 執行Person 的解構子 解構的順序為 ~Derived() -> ~Base()
多重繼承下的虛擬函式 一個衍生類別可能繼承多個基礎類別 注意: 這裡重複繼承了 Base 問題: void main( ) { 考慮下面的 code class Base{ public: void setfield(int val){ field = val; } int getfield() const { return (field); } private: int field; }; void main( ) { Derived obj; obj.getfield(); } 問題: 注意: 這裡重複繼承了 Base class Derived: public Base, public Base{ }; 呼叫哪一個 Base 的 getfield( )
多重繼承下的虛擬函式 多重繼承推導圖與內部結構圖 重複繼承了 Vechicle 佔用了兩份空間 程式很大的時候,則會亦有類似狀況 (因為基礎類別可能不是你寫的) 多重繼承推導圖與內部結構圖 重複繼承了 Vechicle 佔用了兩份空間
解決方法: 虛擬繼承 Virtual Base classes 完整程式範例: VirtualDerived.dsw 解決方法: 虛擬繼承 Virtual Base classes 對於一個 AirAuto, 我們只須要一個 weight. class Land: virtual public Vehicle{ ... }; class Air: virtual public Vehicle{ ... }; 虛擬繼承與虛擬函數不同的地方在於 虛擬繼承完全可以在 compile-time 解析
執行時期的形態辨別 一個基礎類別的指標,可能指的是衍生類別. 那麼我們在執行的時候, 要如何知道這個基礎類別指標到底是指向哪一個物件? class 動物 動物 *p=new 貓; class 貓 重要觀念: 貓是動物的一種. 所以我們可以用動物存取貓. Why? 使得任何的動物種類的物件 都可以用 p 存取. 這就是抽象化,
C++ 的解決方案 typeid 指出目前的指標到底是那一種型態. (傳回字串告訴你) dynamic_cast 運算子來將一個指標轉換成 基礎類別型態 或 衍生類別型態. 在VC中,必須設定才允許使用 dynamic_cast. [project]->[setting...]->[C++]->[C++ Language]: Enable Run-Time Type Information(RTTI)
typeid 範例1 必須先 #include <typeinfo> 在class 中至少要有一個 virtual function 考慮下面的code #include <typeinfo> void main(){ cout << typeid(12).name() << endl; cout << typeid(3.14).name() << endl; } 會印出 int 會印出 double 看 typeid範例2.doc
dynamic_cast 範例 See dynamic_cast.doc