實現和覆寫虛方法的區別:介面中聲明的成員預設不是虛方法。衍生類別不能覆寫基類中實現的介面成員。介面可以被顯式實現,這會使針對該類的公有成員隱藏起來。介面與虛方法的概念不同,用法也不同。
改變從基類繼承的介面在衍生類別中的行為
我們來看一個簡單的例子:
1 interface IMsg 2 { 3 void Message(); 4 } 5 public class MyClass : IMsg 6 { 7 public void Message() 8 { 9 Console.WriteLine("MyClass");10 }11 }12 13 public class MyDerivedClass : MyClass14 {15 public new void Message()16 {17 Console.WriteLine("MyDerivedClass");18 }19 }20 21 public class EffectiveCSharp22 {23 public static void Main(string[] args)24 {25 MyDerivedClass d = new MyDerivedClass();26 d.Message();27 IMsg m = d as IMsg;28 m.Message();29 30 Console.Read();31 }32 }
運行輸出:
我們發現,將MyDerivedClass的執行個體做了轉換之後,調用Message()方法變成了該類基類Class的Message()方法——有時候我們常常需要建立介面,然後在基類中實現它們,並且在衍生類別中更改它們的實現,這時候我們該怎麼辦呢?這時候有兩種辦法可供選擇。
1.將實現介面的基類中實現的介面成員定義成:virtual,並在衍生類別中override
1 interface IMsg 2 { 3 void Message(); 4 } 5 public class MyClass : IMsg 6 { 7 public virtual void Message() 8 { 9 Console.WriteLine("MyClass");10 }11 }12 13 public class MyDerivedClass : MyClass14 {15 public override void Message()16 {17 Console.WriteLine("MyDerivedClass");18 }19 }20 21 public class EffectiveCSharp22 {23 public static void Main(string[] args)24 {25 MyDerivedClass d = new MyDerivedClass();26 d.Message();27 IMsg m = d as IMsg;28 m.Message();29 30 Console.Read();31 }32 }
運行輸出:
2.將實現介面的基類定義成抽象類別,並將實現的介面成員定義為抽象成員
我們同時可以將衍生類別的重寫方法定義成密封的防止其衍生類別再重寫該方法:
1 interface IMsg 2 { 3 void Message(); 4 } 5 public abstract class MyClass : IMsg 6 { 7 public abstract void Message(); 8 } 9 10 public class MyDerivedClass : MyClass11 {12 public sealed override void Message()13 {14 Console.WriteLine("MyDerivedClass");15 }16 }17 18 public class EffectiveCSharp19 {20 public static void Main(string[] args)21 {22 MyDerivedClass d = new MyDerivedClass();23 d.Message();24 IMsg m = d as IMsg;25 m.Message();26 MyClass c = (MyClass)m;27 c.Message();28 Console.Read();29 }30 }
運行輸出:
衍生類別繼承基類中介面的實現
其實衍生類別可以從基類中繼承基類對介面的實現,因為衍生類別可以把該介面的聲明成為其契約的一部分,即使它並沒有實現任何該介面中成員的實現,只要類的某個公開可訪問的方法與介面的簽名相匹配,那麼契約的條件即可滿足,不過這種方法無法使用顯示介面實現。例如下面的樣本:
1 interface IMsg 2 { 3 void Message(); 4 } 5 public abstract class MyClass : IMsg 6 { 7 public virtual void Message() 8 { 9 Console.WriteLine("MyClass");10 }11 }12 13 public class MyDerivedClass : MyClass,IMsg14 {15 }16 17 public class EffectiveCSharp18 {19 public static void Main(string[] args)20 {21 MyDerivedClass d = new MyDerivedClass();22 d.Message();23 IMsg m = d as IMsg;24 m.Message();25 MyClass c = (MyClass)m;26 c.Message();27 Console.Read();28 }29 }
運行輸出:
小節
實現介面擁有的選擇要比建立和覆寫虛函數多。我們可以為類層次建立密封類(sealed)的實現、虛實現或者抽象實現。我們還可以建立密封的實現,並在實現介面的方法中提供虛方法調用。我們也可以決定衍生類別應該如何及何時修改基類中實現的介面成員的預設行為。介面不是虛方法,而是一個單獨的契約。