whitefox 發表於 2023-6-14 15:51:23

[C#] 物件導向 Virtual/Override/Hide 覆寫-隱藏做動規則

本帖最後由 whitefox 於 2024-9-10 14:19 編輯

物件導向中使用虛方法的基本型態是
1. 使用 virtual 修飾詞放在父類別方法宣告前
2. 使用 override 修飾詞放在子類別方法宣告前(或是使用new修飾詞)
覆寫:public class Vehicle
{
    public virtual void Run()
    {
        Console.WriteLine("Base Class - Vehicle Run!");
    }
}

public class Car : Vehicle
{
    public override void Run()
    {
        Console.WriteLine("Derived Class - Car Run!");
    }
}主程式:Vehicle v = new Car();
v.Run();輸出:『Derived Class - Car Run!』

以下這個不常見,軟體開發中基本不會用,若出現基本上都是錯誤情況才會誤用,這邊做個紀錄
取代掉override改用new隱藏,要用this與base區分使用基礎類別的方法還是該子類別的方法
隱藏:public class Vehicle
{
    public virtual void Run()
    {
        Console.WriteLine("Base Class - Vehicle Run!");
    }
}

public class Car : Vehicle
{
    public new void Run()
    {
        Console.WriteLine("Derived Class - Car Run!");
    }
}主程式:Vehicle v = new Car();
v.Run();輸出:『Base Class - Vehicle Run!』

以上兩個例子的主程式中,Vehicle是宣告類別,Car是實體類別
具體的虛方法執行檢查流程如下:

[*]當調用一個物件的方法時,系統會直接去檢查這個物件宣告定義的類別,即宣告類別,看所調用的方法是否為虛方法
[*]如果不是虛方法,那麼它就直接執行該方法。而如果有virtual關鍵字,也就是一個虛方法,那麼這個時候它就不會立刻執行該方法,而是轉去檢查物件的實體類別
[*]在這個實體類別裡,他會檢查這個實體類別的定義中是否有重新實現該虛方法(通過override關鍵字),如果是有,它就不會再找了,而馬上執行該實體類別中的這個重新實現的方法。而如果沒有的話,系統就會不停地往上找實體類別的父類別,並對父類別重複剛才在實體類別裡的檢查,直到找到第一個覆寫了該虛方法的父類別為止,然後執行該類別裡覆寫後的方法


用以下這個例子來統整一下這個規則流程public class A
{
    public virtual void Func() // 注意 virtual, 表示這是一個虛方法
    {
        Console.WriteLine("Class A Func");
    }
}
class B : A // 注意B是從A類別繼承, 所以A是父類別, B是子類別
{
    public override void Func() // 注意 override, 表示重新覆寫虛函數
    {
        Console.WriteLine("Class B Func");
    }
}
class C : B // 注意C是從B類別繼承, 所以B是父類別, C是子類別
{
}
class D : A // 注意D是從A類別繼承, 所以A是父類別, D是子類別
{
    public new void Func() // 注意 new,表示覆蓋父類別裡的同名方法,而不是重新覆寫
    {
        Console.WriteLine("Class D Func");
    }
}主程式:A a;         // 定義一個a這個A類別的物件, 這個A就是a的宣告類別
A b;         // 定義一個b這個A類別的物件, 這個A就是b的宣告類別
A c;         // 定義一個c這個A類別的物件, 這個A就是c的宣告類別
A d;         // 定義一個d這個A類別的物件, 這個A就是d的宣告類別

a = new A(); // 實體化a物件, A是a的實體類別
b = new B(); // 實體化b物件, B是b的實體類別
c = new C(); // 實體化c物件, C是c的實體類別
d = new D(); // 實體化d物件, D是d的實體類別

a.Func();
// 執行a.Func
// 1.先檢查宣告類別A
// 2.檢查到是虛方法
// 3.轉去檢查實體類別A,為虛方法本身
// 4.執行實體類別A中的方法
// 5.輸出結果『Class A Func』

b.Func();
// 執行b.Func
// 1. 先檢查宣告類別A
// 2. 檢查到是虛方法
// 3. 轉去檢查實體類別B,有覆寫的
// 4. 執行實體類別B中的方法
// 5. 輸出結果『Class B Func』

c.Func();
// 執行c.Func
// 1. 先檢查宣告類別A
// 2. 檢查到是虛方法
// 3. 轉去檢查實體類別C,無覆寫的
// 4. 轉去檢查類別C的父類別B, 有覆寫的方法
// 5. 執行父類別B中的Func方法
// 6. 輸出結果『Class B Func』

d.Func();
// 執行d.Func
// 1. 先檢查宣告類別A
// 2. 檢查到是虛方法
// 3. 轉去檢查實體類別D,無覆寫的(這個地方要注意了,雖然D裡有實現Func(),但沒有使用override關鍵字,所以不會被認為是覆寫)
// 4. 轉去檢查類別D的父類別A,為虛方法本身
// 5. 執行父類A中的Func方法
// 6. 輸出結果 『Class A Func』

D d1 = new D();
d1.Func();
// 執行D類別裡的Func(),  輸出結果『Class D Func』
頁: [1]
查看完整版本: [C#] 物件導向 Virtual/Override/Hide 覆寫-隱藏做動規則