乍看之下,介面實作與虛擬函式覆寫都讓衍生類別提供具體實作。但兩者語意、繫結機制、版本演進規則完全不同。
interface IMsg { void Message(); }
public class MyClass : IMsg {
public void Message() => Console.WriteLine("MyClass");
}
public class MyDerivedClass : MyClass {
public new void Message() => Console.WriteLine("MyDerivedClass"); // 隱藏,非覆寫
}
透過 IMsg 參考呼叫 Message() 時,永遠繫結至實作該介面的具體類別,不受衍生關係影響:
MyDerivedClass d = new MyDerivedClass();
d.Message(); // "MyDerivedClass"
((IMsg)d).Message(); // "MyClass" —— 介面繫結至 MyClass 實作!
((MyClass)d).Message(); // "MyClass"
class MyDerived : MyClass, IMsg),但需加 new 隱藏基類實作,基類參考仍呼叫舊版本。public class MyClass : IMsg {
public virtual void Message() => Console.WriteLine("MyClass");
}
public class MyDerivedClass : MyClass {
public override void Message() => Console.WriteLine("MyDerivedClass");
}
// 現在所有管道(衍生類別參考、基類參考、介面參考)皆呼叫覆寫版本
public abstract class MyClass : IMsg {
public abstract void Message(); // 介面方法以抽象方法實作
}
所有衍生類別必須覆寫實作,介面契約內建於類別階層中。
public struct Customer : IComparable {
int IComparable.CompareTo(object obj) { ... } // 僅透過 IComparable 存取
public int CompareTo(Customer other) { ... } // 型別安全公開版本
}
消費者無法直接呼叫 非型別安全版本,必須強制轉型為介面,配合原則 26 型別安全多載模式完美運作。
| 特性 | 介面實作 | 虛擬函式覆寫 |
|---|---|---|
| 繫結時機 | 編譯期(依實作類別) | 執行期(依物件型別) |
| 衍生類別修改行為 | 需重新實作介面或基類改 virtual | 直接 override |
| 版本演進 | 介面一旦發布不可變 | 可新增 virtual 成員 |
| 多重實作 | 支援顯性實作解決衝突 | 單一繼承鏈 |
virtual。