class CA { public virtual void Foo() { Console.WriteLine("CA.Foo"); } }
class CB : CA { public override void Foo() { Console.WriteLine("CB.Foo"); } }
class Test {
public static void InvokeFoo(CA ca) { ca.Foo(); }
public static void Main() { InvokeFoo(new CB()); } // 輸出: CB.Foo
}
關鍵字:virtual(啟用運行時綁定)、override(覆寫基類實現)
| 基類 virtual | 子類 override | 輸出 | 說明 |
|---|---|---|---|
| 是 | 是 | CB.Foo | 正常多態 |
| 是 | 否 | CA.Foo | 運行時綁定,但子類未覆寫 |
| 否 | 是 | 編譯錯誤 | 非虛方法不可 override |
| 否 | 否 | CA.Foo | 編譯時靜態綁定 |
class CA { public virtual void Foo() { Console.WriteLine("CA.Foo"); } }
class CB : CA { public override void Foo() { Console.WriteLine("CB.Foo"); } }
class CC : CA { public new void Foo() { Console.WriteLine("CC.Foo"); } } // 隱藏
class Test {
public static void Main() {
Console.WriteLine(typeof(CB).GetMethods().Length); // 5 (含 1 個 Foo)
Console.WriteLine(typeof(CC).GetMethods().Length); // 6 (含 2 個 Foo)
}
}
override:替換基類虛方法槽位,方法數不增加new:隱藏基類方法,新增獨立方法槽位(IL 級別為 virtual final)new(編譯器警告)interface IA { void Foo(); }
class CA : IA {
public void Foo() { Console.WriteLine("CA.Foo"); } // 隱式 virtual final
}
virtualvirtual 才允許子類覆寫interface IA { void Foo(); }
class CA : IA { public virtual void Foo() { Console.WriteLine("CA.Foo"); } }
class CB : CA, IA { public void Foo() { Console.WriteLine("CB.Foo"); } } // 無 override、無 virtual
class Test {
public static void InvokeFoo(CA ca) { ca.Foo(); }
public static void Main() {
InvokeFoo(new CA()); // 輸出?
InvokeFoo(new CB()); // 輸出?
}
}
思考:CB.Foo 會被調用嗎?為什麼?(答案:CB.Foo 隱藏 CA.Foo,但 CA.Foo 仍為虛方法,CB 未 override,故調用 CA.Foo)
virtual:方法槽位可被覆寫final:封鎖覆寫(C# sealed)newslot:強制分配新虛方法槽位(C# new 隱藏).NET 虛函數機制核心在於虛方法表槽位管理。virtual 開啟槽位,override 替換槽位內容,new 分配新槽位,sealed 封鎖槽位。介面實現預設 virtual final,需顯式 virtual 開放覆寫。理解 IL 層面機制,能精準控制多態行為,避免隱藏導致的難診斷 Bug。