關於虛方法virtual和抽象方法以及多型的研究
虛方法virtual定義:
當類中的方法宣告前加上了virtual 修飾符,我們稱之為虛方法,反之為非虛。使用了virtual 修飾符後,不允許再有static, abstract, 或override 修飾符(必須是Public)。 為了實現多型,父類裡面的方法用虛方法,子類裡面可以對該方法重寫,也可以不重寫,當我們建立了一個子類 的物件並把它轉換成了父類的型別後,如果子類裡面沒有重寫父類裡面的虛方法,則直接呼叫父類的方法,如果子類 裡面重寫了虛方法,則呼叫子類時面重寫後的方法。
虛方法和非虛方法什麼區別呢?
對於非虛的方法,無論被其所在類的例項呼叫,還是被這個類的派生類的例項呼叫,方法的執行方式不變
結果是:class A 2 { 3 public void F() { Console.WriteLine("A.F"); } 4 public virtual void G() { Console.WriteLine("A.G"); } //定義虛方法 5 } 6 class B : A 7 { 8 new public void F() { Console.WriteLine("B.F"); } //這裡的方法則不能重寫,因為基類中的F()方法不是虛方法。 9 public override void G() { Console.WriteLine("B.G"); } //重寫虛方法 10 } 11 static void Main(string[] args) 12 { 18 B b = new B(); 19 A a = b; //A物件指向B物件 20 b.F(); //顯示結果B.F 21 a.F(); //顯示結果A.F 22 b.G(); //顯示結果B.G 23 a.G(); //顯示結果B.G 實際這裡呼叫的是不是基類中的G方法,而是派生類中重寫過的G方法。 24 Console.ReadKey(); 25 }
B.F
A.F
B.G
B.G
a.G()的結果是B.G。這裡了可以得出結論,當基類物件指向派生類物件時,基類的虛方法被重寫,函式執行的是派生類方法。不是虛方法呼叫的是基類方法。
非虛擬方法的實現是不變的:無論是在宣告它的類的例項上呼叫該方法還是在派生類的例項上呼叫,實現都是相同的。與此相反,虛擬方法的實現可以由派生類取代。取代所繼承的虛擬方法之實現的過程稱為重寫方法
這裡的new 是在子類對父類方法的一種替換,不寫會有警告;
與抽象方法什麼區別呢?
一、抽象方法的使用: 1、方法前加abstract,同時在類前也要加abstract(必須要加),這個類稱為抽象類,方法要是public。4、任何一個非抽象子類必須要重寫父類的抽象方法。 二、區別: 1、抽象方法在父類裡面一定不可以實現,即要有方法體(就是方法後面有沒有大括號{ }),而虛方法在父類時面一定要帶方法體; 2、抽象方法在子類裡面一定要實現,虛方法在子類裡面可以不用重寫,也可以重寫(重寫要實現)。二者都可以看做多型的範疇,這些多用在設計模式上寫大型的遊戲時多用在搭框架。 (C#中寫方法的時候,除了介面和抽象方法,其它的基本都帶方法體)
這兩者都是多型的範疇,多型怎麼理解?
多型是我們在寫方法時,為了使程式碼的重用性達到最大,通常都會把子類的物件轉換成父類,但是在調方法時只能調到父類裡面的方法,而子類裡面的方法調不到,但是每個子類又有各自的行為,此時用到多型,子類時面重寫父類裡面的方法,,但子類在調同一個方法時,都會調到各自重寫的方法,這樣型別也達到了統一,處理起來也方法,同時也體現了子類 的各自的行為.(粗糙的說多型是和重寫方法同時出現的,因為重寫了就實現了多型,如果不重寫,所有的子類呼叫父類的虛方法都是一樣的,但是這樣的話不要說出來,自己理解可以這樣理解 ,說出來別人會認為你外行了。) 另外介面也可以實現多型,多個類繼承一個介面,各自類進行不同的實現後,不同的類呼叫接口裡面的方法 ,這樣也實現了多型。虛方法,抽象 方法和介面都可以實現多型,設計模式裡面大多用到介面。重寫的概念:
是子類(即派生類)的方法覆蓋父類(即基類)的虛方法。
重寫的要求:
1、三相同:
(1)方法名稱相同
(2)引數列表相同
(3)返回值型別相同
一句話,只需重寫程式碼體的內容!
2、重寫宣告不能更改虛方法的可訪問性:重寫方法和虛方法必須具有相同的訪問級修飾符。例如:虛方法為public的,重新方法也必須是public的。
3、可以重寫基方法:必須是虛擬的(virtual)、抽象的(abstract)或重寫的(override)。(非虛方法或靜態方法是不可以重寫的)。
4、不能使用下列修飾符修改重寫(override)方法(即該方法中含有override關鍵字):new、static、virtual、abstract
如:new public override void outwork () //這樣寫是不可以的
{
MessageBox.Show("子類的子類(override)下班");
}
5、重寫屬性:重寫的屬性必須與繼承屬性有完全相同的訪問修飾符、型別和屬性名,並且重寫屬性必須是虛擬的(virtual)、抽象的(abstract)或是重寫的(override)。
6、new關鍵字和override關鍵字比較:
如果使用override重寫xx方法,通過父類引用一樣只能看到重寫後的方法; override重寫的是虛方法,那麼就只剩下重寫以後的方法,原來的方法被覆蓋了。如果使用new隱藏xx方法,父類子類引用各自對應方法;new隱藏基類的方法,那麼基類的方法和當前類的方法同時存在只是被隱藏了。
總結:override可以覆蓋基類的方法,讓基類的方法以子類的內容實現,而new不用來覆蓋基類的方法,而是全新定義一個子類的方法,這個方法只屬於子類,與基類的方法無關,只是名字上相同而已。