Virtual Function

Download Report

Transcript Virtual Function

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