class Base
{
public virtual void PrintStatus()
=> Console.WriteLine("Base.PrintStatus");
}
class Derived1 : Base
{
public override void PrintStatus()
=> Console.WriteLine("Derived1.PrintStatus");
}
統一處理:
void DisplayStatus(Base[] items)
{
foreach (var b in items) b.PrintStatus(); // 動態綁定
}
class Derived2 : Base
{
public new void PrintStatus()
=> Console.WriteLine("Derived2.PrintStatus (new 隱藏)");
}
Base[] items = { new Base(), new Derived1(), new Derived2() };
DisplayStatus(items);
// 輸出:
// Base.PrintStatus
// Derived1.PrintStatus
// Base.PrintStatus ← Derived2 以 Base 型別調用時,調用的是 Base 版本!
new 只是隱藏基類成員,不參與虛擬調度。可通過型別轉換「解封」:
Base d2 = new Derived2();
d2.PrintStatus(); // 輸出 Base.PrintStatus
// Derived2 內部可用 base 訪問被隱藏成員
base.PrintStatus();
class Base { public static void S() => Console.WriteLine("Base.S"); }
class Derived : Base { public new static void S() => Console.WriteLine("Derived.S"); }
// 必須透過類別名稱調用
Base.S(); // Base.S
Derived.S(); // Derived.S
interface IFace { void PrintStatus(); }
class Base : IFace
{
public virtual void PrintStatus() => Console.WriteLine("Base");
}
class Derived2 : Base, IFace
{
public new void PrintStatus() => Console.WriteLine("Derived2 (new + 介面重新實作)");
}
透過介面調用時,new 方法參與動態綁定:
IFace[] fs = { new Base(), new Derived1(), new Derived2() };
foreach (var f in fs) f.PrintStatus();
// 輸出:
// Base
// Derived1
// Derived2 (new + 介面重新實作) ← 介面綁定生效!
原理:new 切斷與 Base.PrintStatus 的虛擬槽關聯,但 Derived2 重新宣告實作 IFace,編譯器將其視為介面槽的新實作。
Base 宣告 virtual 期望多態,Derived2 用 new 違背契約 → Derived2 應改名或用 overrideDerived2 確實不想參與多態 → Base 應考慮移除 virtual 或改為 abstract 強制衍生類實作abstract class Base { public abstract void PrintStatus(); }
class Derived3 : Base
{
public override void PrintStatus() => Console.WriteLine("Derived3 (原 Base 實作下移)");
}
// 此時 Derived2 若仍用 new PrintStatus() → 編譯錯誤,強制修正
Stream.Seek 為 abstract,但 NetworkStream 不支援定位,調用拋 NotSupportedException。設計模式:
CanSeek、CanRead、CanWrite 屬性讓調用者預檢if (stream.CanSeek) stream.Seek(...); else 降級處理| 關鍵字 | 語義 | 虛擬槽 | 介面槽 |
|---|---|---|---|
virtual | 開放覆寫 | 新增/繼承 | 可實作 |
override | 覆寫基類虛擬/抽象 | 替換 | 替換 |
new | 隱藏基類同名成員 | 切斷關聯 | 可重新實作介面 |
abstract | 強制衍生類實作 | 無實作槽 | 需實作 |
核心心法:virtual = 契約承諾,override = 履行契約,new = 拒絕契約 (或另闢蹊徑)。設計時優先用 abstract 強制語義清晰,謹慎使用 new 並配合介面重新實作解耦。