C#的方法引入了virtual、override、sealed、abstract四種修飾符來提供不同的繼承需求。類的虛方法是可以在該類的繼承類中改變其實作的方法,當然這種改變僅限于方法體的改變,而非方法頭(方法聲明)的改變。被子類改變的虛方法必須在方法頭加上override來表示。當一個虛方法被調用時,該類的執行個體——亦即對象的運作時類型(run-time type)來決定哪個方法體被調用。看下面的例子:
using System;
class Parent
{ public void F() {
Console.WriteLine(“Parent.F”); }
public virtual void G() {
Console.WriteLine(“Parent.G”); }
}
class Child: Parent
{ new public void F() {
Console.WriteLine(“Child.F”); }
public override void G() {
Console.WriteLine(“Child.G”); }
}
class Test
{
static void Main()
{ Child b = new Child();
Parent a = b;
a.F();
b.F();
a.G();
b.G();
}
}
程式經編譯後執行,輸出:
Parent.F
Child.F
Child.G
Child.G
可以看到類Child中F()方法的聲明采取了重寫(new)來屏蔽父類中的非虛方法F()的聲明,而G()方法采用了覆寫(override)來提供方法的多态機制。需要注意的是重寫(new)方法和覆寫(override)的不同,從本質上講重寫方法是編譯時綁定,而覆寫方法是運作時綁定。值得指出的是虛方法不可以是靜态方法——也就是說不可以用static和virtual同時修飾一個方法,這是由它的運作時類型辨析機制所決定的。override必須和virtual配合使用,當然也就不能和static同時使用。
如果在一個類的繼承體系中不想再使一個虛方法被覆寫,該怎樣做呢?答案是sealed override(密封覆寫),用sealed和override同時修飾一個虛方法便可以達到這種目的: sealed override public void F()。注意這裡一定是sealed和override同時使用,也一定是密封覆寫一個虛方法,或者一個被覆寫(而不是密封覆寫)了的虛方法。密封一個非虛方法是沒有意義的,也是錯誤的。
抽象(abstract)方法在邏輯上類似于虛方法,隻是不能像虛方法那樣被調用,是一個接口的聲明而非實作。抽象方法沒有方法實作,也不允許這樣做。抽象方法同樣不能是靜态的。含有抽象方法的類一定是抽象類,也一定要加abstract類修飾符。但抽象類并不一定要含有抽象方法。繼承含有抽象方法的抽象類的子類必須覆寫并實作(直接使用override)該方法,或者組合使用abstract override使之繼續抽象,或者不提供任何覆寫和實作,後兩者的行為是一樣的。看下面的例子:
using System;
abstract class Parent
{ public abstract void F();
public abstract void G(); }
abstract class Child: Parent
{ public abstract override void F();}
abstract class Grandson: Child
{
public override void F()
{ Console.WriteLine(“Grandson.F”);}
public override void G()
{ Console.WriteLine(“Grandson.G”);}
}
抽象方法可以抽象一個繼承來的虛方法。抓住了運作時綁定和編譯時綁定的基本機理,便能看透方法呈現出的overload、virtual、override、sealed、abstract等形态。