關於C#中的new修飾符以及override關鍵字

今天一朋友問我,C#中 new 與 override 有什麼區別?
附上原問題導航C#中的new與Override的區別?(SF上的各位都是朋友,嘿嘿)。
剛看到這個問題,其實我有點懵,由於我對這兩個關鍵字的研究也沒有花太多心思,雖然知道一些區別,但並非很是確信。
因此,趁着此次機會,本身也學習一下。c#

首先,原問題中的示例代碼給了我很是好的參考。這段代碼很是直觀地體現了newoverride的區別。segmentfault

下面是我略加整理的測試代碼:ide

new修飾符

代碼

public class FatherNew
{
    public void DoConsole()
    {
        Console.WriteLine("New修飾符 => 父類。");
    }

    public void ConsoleFather()
    {
        DoConsole();
    }
}

public class ChildNew : FatherNew
{
    public new void DoConsole()
    {
        Console.WriteLine("New修飾符 => 子類。");
    }

    public void ConsoleFatherCopy()
    {
        DoConsole();
    }
}
// 客戶端調用
var cn = new ChildNew();
cn.ConsoleFather();
// cn.ConsoleFatherCopy(); // 這一句會輸出 "New修飾符 => 子類。",具體緣由結論中會說明。

代碼中,咱們使用new隱藏了父類(FatherNew)的DoConsole方法。
看看它的運行結果吧。學習

運行結果

new result

那麼問題來了:咱們明明把FatherDoConsole方法覆蓋掉了,理論上ConsoleFather()執行的時候應該調用新的DoConsole呀,這樣的話,應該輸出"New修飾符 => 子類。"纔對呀。測試

這個疑惑我們先放放,先看一下override的代碼及結果我們再統一總結。spa

override修飾符

代碼

public class FatherOverride
{
    public virtual void DoConsole()
    {
        Console.WriteLine("Override修飾符 => 父類。");
    }
    public void ConsoleFather()
    {
        DoConsole();
    }
}

public class ChildOverride : FatherOverride
{
    public override void DoConsole()
    {
        Console.WriteLine("Override修飾符 => 子類。");
    }

    public void ConsoleFatherCopy()
    {
        DoConsole();
    }
}
// 客戶端調用
var co = new ChildOverride();
co.ConsoleFather();

就像new裏的代碼同樣,咱們重寫了父類(FatherOverride)的DoConsole方法,只不過此次是用override修飾符。
也看看運行結果吧:code

運行結果

override result

這個還算符合預期,既然我重寫了DoConsole,那麼執行時,就應該執行調用新的DoConsole纔對嘛。對象

結論

new修飾符定義的新方法,在同一派生類調用時,的確會調用這個新的方法,但在其基類中調用時,依舊是調用基類中的那個原始的方法。
override修飾符重寫的方法,只要是經過派生類實例調用,哪怕是間接調用(好比像示例代碼中,派生類的示例,調用父類中的ConsoleFather方法),都會調用新的使用override重寫的那個方法。blog

之因此出現這種狀況,是由於在編譯時,它們就已經有了差別:get

普通成員在編譯時,其引用的相對地址就已經被程序肯定好了。所以程序運行時,將會直接根據編譯時就肯定好了的地址調用該成員。即:在編譯時, FatherNewConsoleFather方法就已經肯定了它內部持有的 DoConsole方法就是 FatherNewDoConsole方法。所以,程序運行時,天然也就會調用 FatherNewDoConsole方法,因此,輸出的結果固然也就是 "New修飾符 => 父類。"了。
cn.ConsoleFatherCopy()之因此會輸出 "New修飾符 => 子類。",也是由於 ChildNew在編譯時,就已經決定了 ConsoleFatherCopy中持有的是 ChildNewDoConsole方法的引用。

而虛成員在編譯時,並無將其引用固定寫在程序的執行文件中。所以程序運行時,纔會檢查當前對象(也就是類的實例)究竟是什麼類型。當該對象調用虛成員時,會發現該成員是虛成員,而後就會查找它的重寫成員。從該實例的類開始,一層一層地向上(即其父類)查找,找到後就會執行。即:ChildOverride實例化後,調用其基類中的ConsoleFather時,程序還不知道DoConsole的具體引用地址。查找後發現這個虛方法的第一個重寫就是ChildOverride中的DoConsole,所以,就執行它了。

相關文章
相關標籤/搜索