今天一朋友問我,C#中 new 與 override 有什麼區別?
附上原問題導航C#中的new與Override的區別?(SF上的各位都是朋友,嘿嘿)。
剛看到這個問題,其實我有點懵,由於我對這兩個關鍵字的研究也沒有花太多心思,雖然知道一些區別,但並非很是確信。
因此,趁着此次機會,本身也學習一下。c#
首先,原問題中的示例代碼給了我很是好的參考。這段代碼很是直觀地體現了new
和override
的區別。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
方法。
看看它的運行結果吧。學習
那麼問題來了:咱們明明把Father
的DoConsole
方法覆蓋掉了,理論上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
這個還算符合預期,既然我重寫了DoConsole
,那麼執行時,就應該執行調用新的DoConsole
纔對嘛。對象
new
修飾符定義的新方法,在同一派生類調用時,的確會調用這個新的方法,但在其基類中調用時,依舊是調用基類中的那個原始的方法。override
修飾符重寫的方法,只要是經過派生類實例調用,哪怕是間接調用(好比像示例代碼中,派生類的示例,調用父類中的ConsoleFather
方法),都會調用新的使用override
重寫的那個方法。blog
之因此出現這種狀況,是由於在編譯時,它們就已經有了差別:get
普通成員在編譯時,其引用的相對地址就已經被程序肯定好了。所以程序運行時,將會直接根據編譯時就肯定好了的地址調用該成員。即:在編譯時,FatherNew
的ConsoleFather
方法就已經肯定了它內部持有的DoConsole
方法就是FatherNew
的DoConsole
方法。所以,程序運行時,天然也就會調用FatherNew
的DoConsole
方法,因此,輸出的結果固然也就是"New修飾符 => 父類。"
了。
而cn.ConsoleFatherCopy()
之因此會輸出"New修飾符 => 子類。"
,也是由於ChildNew
在編譯時,就已經決定了ConsoleFatherCopy
中持有的是ChildNew
的DoConsole
方法的引用。而虛成員在編譯時,並無將其引用固定寫在程序的執行文件中。所以程序運行時,纔會檢查當前對象(也就是類的實例)究竟是什麼類型。當該對象調用虛成員時,會發現該成員是虛成員,而後就會查找它的重寫成員。從該實例的類開始,一層一層地向上(即其父類)查找,找到後就會執行。即:
ChildOverride
實例化後,調用其基類中的ConsoleFather
時,程序還不知道DoConsole
的具體引用地址。查找後發現這個虛方法的第一個重寫就是ChildOverride
中的DoConsole
,所以,就執行它了。