核心差異一覽表
| 維度 | override (重寫) | overload (多載) |
| 目的 | 改寫基底類別虛擬成員行為 | 同類別提供同名不同參數方法 |
| 發生位置 | 衍生類別 | 同一類別內 |
| 前置條件 | 基底成員為 virtual/abstract/override | 無特殊要求 |
| 方法簽章 | 必須完全相同(名稱、參數、回傳型別) | 參數型別/數量/順序不同 |
| 多型行為 | 執行時動態分派 | 編譯時靜態綁定 |
| 關鍵字 | override | 無關鍵字(單純同名) |
經典範例
using System;
class BaseClass {
public virtual void F() => Console.WriteLine("BaseClass.F");
}
class DerivedClass : BaseClass {
// override:重寫基底虛擬方法
public override void F() {
base.F(); // 可選:呼叫基底實作
Console.WriteLine("DerivedClass.F");
}
// overload:同類別多載
public void Add(int left, int right) => Console.WriteLine($"Add Int: {left + right}");
public void Add(double left, double right) => Console.WriteLine($"Add Double: {left + right}");
public void Add(int left, int right, int third) => Console.WriteLine($"Add 3 Int: {left + right + third}");
}
class Program {
static void Main() {
DerivedClass obj = new DerivedClass();
obj.F(); // BaseClass.F / DerivedClass.F
obj.Add(1, 2); // Add Int: 3
obj.Add(1.1, 2.2); // Add Double: 3.3
Console.ReadKey();
}
}
輸出結果
BaseClass.F
DerivedClass.F
Add Int: 3
Add Double: 3.3
進階陷阱與最佳實踐
1. 隱藏 vs 重寫(new vs override)
class Base { public virtual void M() => Console.WriteLine("Base"); }
class Derived : Base {
public new void M() => Console.WriteLine("Derived"); // 隱藏,非重寫
}
Base b = new Derived();
b.M(); // 輸出 "Base" (靜態綁定至 Base.M)
((Derived)b).M(); // 輸出 "Derived"
- 預設不加關鍵字 =
new 隱藏(編譯器警告 CS0108)
- 一定要用
override 實現多型
2. 多載解析規則
- 優先精確匹配
- 隱含轉換(
int → long、Derived → Base)
params 最後考慮
- 泛型 vs 非泛型:非泛型優先
3. 回傳型別不參與多載簽章
// 錯誤:僅回傳型別不同無法多載
public int Parse(string s) { }
public double Parse(string s) { } // CS0111
4. 覆寫時回傳型別共變
class Base { public virtual object Get() => null; }
class Derived : Base { public override string Get() => ""; } // 合法:string 繼承 object
設計指南
- override:擴充/修改基底行為,保留 Liskov 替換原則
- overload:提供便利 API(預設參數、型別轉換、參數組合)
- 避免過度多載:超過 3-4 個多載考慮改用
params、建構器模式、選項物件
- 文檔標註
<inheritdoc/> 繼承基底 XML 註解