偶然間看到的題,借此記錄。
class Program{static void Main(string[] args){D d = new D(); //第一個D是申明類,第二個D是實例類A a = d;B b = d;C c = d;a.F();b.F();c.F();d.F();}class A{public virtual void F() { Console.WriteLine("A.F"); }}class B : A{public override void F() { Console.WriteLine("B.F"); }}class C : B{public virtual void F() { Console.WriteLine("C.F"); }}class D : C{public override void F() { Console.WriteLine("D.F"); }}}
輸出結果:
下面記錄一下解題步驟:
a.F();? >>>? 1. 檢查申明類A 2. 是虛方法 3. 繼續檢查實例類D 4. 有重寫,但是相對于類A來說Fun()在類C中被new 過,根據口訣“new則看類型,override只管新” 5. 繼續檢查父類B 6. 類B中override了父類A的 Fun() 7. 執行類B中的Fun(),輸出B.F
b.F();? >>>? 1. 檢查申明類B 2. 不是虛方法 3. 直接執行類B中的Fun(),輸出B.F
c.F();? >>>? 1. 檢查申明類C 2. 是虛方法 3. 繼續檢查實例類D 4. 有重寫,類D重寫了類C中的Fun(),根據口訣“new則看類型,override只管新” 5. 執行類D中的Fun(),輸出D.F
d.F();? >>>? 1. 檢查申明類D 2. 不是虛方法 3. 直接執行類D中的Fun(),輸出D.F
摘用一下別人特別好的總結:
具體的檢查的流程如下
1、當調用一個對象的函數時,系統會直接去檢查這個對象申明定義的類,即申明類,看所調用的函數是否為虛函數;
2、如果不是虛函數,那么它就直接執行該函數。而如果有virtual關鍵字,也就是一個虛函數,那么這個時候它就不會立刻執行該函數了,而是轉去檢查對象的實例類。
3、在這個實例類里,他會檢查這個實例類的定義中是否有重新實現該虛函數(通過override關鍵字),如果是有,那么OK,它就不會再找了,而馬上執行該實例類中的這個重新實現的函數。而如果沒有的話,系統就會不停地往上找實例類的父類,并對父類重復剛才在實例類里的檢查,直到找到第一個重載了該虛函數的父類為止,然后執行該父類里重載后的函數。
?在上面的規則中,可以看到,如果子類沒有override的修飾,那么就算父類是virtual的方法,子類的方法也無法被調用,而會去它的父類中找override的方法,直到找到祖先類。所以在面向對象的開發過程中,如果要實現Dependency Injection、IoC等設計模式,就必須非常留意類設計中繼承方法的聲明,否則很可能導致實際的程序運行與預期不符。
?引用:https://www.cnblogs.com/yanyao/p/4830768.html