多型本質:一介面、多實作、動態分派
多型讓用戶端程式碼依賴抽象介面 (基類/介面),執行時根據物件實際型別自動選擇正確實作。C# 透過 虛方法 + 覆寫 實現執行時多型 (Subtype Polymorphism)。
三大支柱
| 關鍵字 | 角色 | 位置 |
virtual | 基類宣告可被覆寫的方法 | 基類 |
override | 衍生類別提供新實作 | 衍生類別 |
base | 呼叫基類實作 (可選) | 衍生類別覆寫方法內部 |
經典範例:交通工具鳴笛
public class Vehicle
{
public virtual void Honk() => Console.WriteLine("Vehicle honk!");
}
public class Car : Vehicle
{
public override void Honk() => Console.WriteLine("Beep beep!");
}
public class Truck : Vehicle
{
public override void Honk() => Console.WriteLine("Hooooonk!");
}
public class Test
{
public static void Main()
{
Vehicle v = new Vehicle(); v.Honk(); // Vehicle honk!
v = new Car(); v.Honk(); // Beep beep!
v = new Truck(); v.Honk(); // Hooooonk!
}
}
動態繫結原理
- 編譯期:根據宣告型別 (
Vehicle) 檢查方法是否存在
- 執行期:根據實際型別 (
Car/Truck) 透過虛方法表 (v-table) 跳轉到正確實作
- 這就是「動態多型」:同一行程式碼
v.Honk(),執行時行為不同
覆寫規則詳解
| 規則 | 正確範例 | 錯誤範例 |
| 簽章必須完全一致 | override void Foo(int x) | override void Foo(string x) |
| 存取層級不可縮小 | 基類 protected → 衍生 public | 基類 public → 衍生 private |
| 不可移除 virtual/abstract | override void Foo() | new void Foo() (隱藏非多型) |
| 不可加上 static/private | | static override void Foo() |
| 可呼叫 base.Method() | base.Honk(); | |
虛方法 vs. 抽象方法 vs. 介面方法
| 特性 | virtual | abstract | interface |
| 基類可有實作 | 是 | 否 | C# 8+ 可有預設 |
| 衍生類別強制實作 | 否 | 是 | 是 |
| 適用場景 | 有合理預設行為 | 無預設/必須自訂 | 跨型別契約 |
進階:密封覆寫
public class Base { public virtual void Foo() { } }
public class Middle : Base { public sealed override void Foo() { } } // 封鎖進一步覆寫
public class Derived : Middle { public override void Foo() { } } // CS0239: 無法覆寫 sealed 方法
多型最佳實踐
- 優先使用介面 定義契約,抽象類別提供共用實作
- 虛方法保持簡單,複雜邏輯委派給非虛輔助方法 (Non-Virtual Interface 模式)
- 避免在建構函式呼叫虛方法:衍生類別尚未初始化,可能導致 NullReference
- 文件化覆寫契約:XML 註解說明何時呼叫
base、預期行為、副作用
總結
C# 多型建立在 virtual/override 機制上,編譯期綁定宣告型別,執行期分派實際型別。掌握簽章一致性、存取層級、base 呼叫時機、sealed 封鎖等規則,能寫出安全且可擴充的物件導向程式碼。
- 上一篇文章: C# 抽象類別深度解析:定義規則、實例化限制與繼承鏈實作
- 下一篇文章: C# 虛方法覆寫實戰:override 關鍵字、簽章一致性與動態分派範例
Copyright ©
程式碼之家 All Rights Reserved