| 機制 | 關鍵字 | 簽章要求 | 多型性 | 用途 |
| 覆寫 | override | 完全一致 | 是 (動態分派) | 擴充/修改基類行為 |
| 多載 | 無 (同名不同參數) | 參數不同 | 否 (靜態綁定) | 提供便利呼叫方式 |
| 隱藏 | new | 任意 | 否 (靜態綁定) | 刻意切斷繼承鏈 |
覆寫語法鐵律
public class Base
{
public virtual void Foo(int x) { } // 虛方法
public virtual int Bar(string s) => 0; // 虛方法有回傳值
public abstract void AbstractMethod(); // 抽象方法隱含 virtual
}
public class Derived : Base
{
// 正確覆寫:簽章完全一致 + override
public override void Foo(int x) { base.Foo(x); /* 擴充 */ }
public override int Bar(string s) => base.Bar(s) + 1;
// 錯誤範例:
// public override void Foo(string x) { } // CS0508: 簽章不符
// public new void Foo(int x) { } // 隱藏非覆寫 (警告 CS0108)
// public virtual override void Foo(int x) { } // CS0506: 不可加 virtual
// private override void Foo(int x) { } // CS0507: 不可縮小存取權
}
完整動態分派範例
public class Vehicle
{
public int Wheels { get; set; }
public virtual void Honk() => Console.WriteLine("Vehicle honk!");
}
public class Car : Vehicle
{
public int Passengers { get; set; }
public Car(int p) { Passengers = p; Wheels = 4; }
public override void Honk() => Console.WriteLine("Beep beep!");
}
public class Truck : Vehicle
{
public float Load { get; set; }
public Truck(float l) { Load = l; Wheels = 6; }
public override void Honk() => Console.WriteLine("Hooooonk!");
}
public class Test
{
public static void Main()
{
Vehicle v = new Vehicle();
Car c = new Car(5);
Truck t = new Truck(10f);
v.Honk(); // Vehicle honk!
v = c; v.Honk(); // Beep beep! (實際型別 Car)
c.Honk(); // Beep beep!
v = t; v.Honk(); // Hooooonk! (實際型別 Truck)
t.Honk(); // Hooooonk!
}
}
基類呼叫時機與模式
public override void Honk()
{
// 模式 1:前置處理 → 基類 → 後置處理
Console.Write("Car: ");
base.Honk(); // 呼叫基類實作
Console.WriteLine(" (done)");
// 模式 2:完全取代 (不呼叫 base)
// public override void Honk() => Console.WriteLine("Beep beep!");
// 模式 3:條件式呼叫
// if (someCondition) base.Honk();
}
原則:若基類實作包含必要邏輯 (資源釋放、事件觸發、不變條件維護),務必呼叫 base;否則可完全取代。
抽象方法覆寫:強制實作契約
public abstract class Animal
{
public abstract void MakeSound(); // 無實作,隱含 virtual
}
public class Dog : Animal
{
public override void MakeSound() => Console.WriteLine("Woof!");
}
// 編譯器強制 Dog 必須 override MakeSound
常見錯誤與除錯
| 錯誤代碼 | 原因 | 修正 |
| CS0506 | 覆寫方法加上 virtual | 移除 virtual |
| CS0507 | 覆寫方法存取層級較基類嚴格 | 調整為相同或更寬鬆 |
| CS0508 | 回傳型別/參數不符 | 修正簽章完全一致 |
| CS0115 | 標記 override 但基類無虛/抽象方法 | 檢查基類簽章或移除 override |
| CS0239 | 嘗試覆寫 sealed 方法 | 移除 sealed 或放棄覆寫 |
設計建議
- 虛方法要有明確契約:XML 註解說明預期行為、
base 呼叫時機、例外保證
- 非虛介面模式 (NVI):公開非虛方法封裝邏輯,呼叫受保護虛方法:
public void Process() { Validate(); DoProcess(); Notify(); } // 非虛
protected virtual void DoProcess() { } // 可覆寫核心
- 避免深層覆寫鏈:超過 3 層難以維護,考慮組合/策略模式替代
- 上一篇文章: C# 多型核心機制:虛方法、覆寫與動態繫結完整指南
- 下一篇文章: 深入理解 C# 虛擬方法與多態機制
Copyright ©
程式碼之家 All Rights Reserved