C井中virtual方法與abstract方法的區別

C井中virtual方法與abstract方法的區別 (轉自:http://www.cnblogs.com/yjmyzz/archive/2010/03/30/1700419.html)

 

先直接看代碼吧:

using System; 

  

 namespace ConsoleApplication1 

     class Program 

     { 

         static void Main(string[] args) 

         { 

             B b = new B(); 

             b.Method1();    

            Console.ReadLine(); 

         } 

     } 

     class A  

     { 

         public virtual void Method1() { 

            Console.WriteLine("A.Method1"); 

         } 

     }     

     class B : A  

     { 

         public void Method1()  

         { 

             Console.WriteLine("B.Method1"); 

         } 

     } 

 }

這段代碼很簡單:B繼承A,然後定義了一個A中的同名方法Method1,編譯能通過,但是會提示警告:

'ConsoleApplication1.B.Method1()' hides inherited member 'ConsoleApplication1.A.Method1()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

即:B.Method1隱藏了繼承自A的Method1方法,如果您想重定義該方法的實現,請添加override關鍵字,否則增加new關鍵字.

用Reflector查看下最終B中的Method1定義對應的IL代碼:


如果我們要消除這種編譯警告,可以嘗試在前面加一個new關鍵字,即變成:

class B : A  

     { 

         new public void Method1()  

         { 

             Console.WriteLine("B.Method1-->new"); 

         } 
還是來看下這時的IL代碼:

對比一下,發現跟沒加new沒啥區別,即編譯器發現同名方法定義後,針對於本例中的情況,默認是當作new關鍵字來處理的
如果把new換成override關鍵字,即:

class B : A   
{  
     override public void Method1()   
     {  
         Console.WriteLine("B.Method1-->override");  
     }  
}

這時的IL定義如下:

可以發現多了一個virtual,即加了override後,編譯器把B類中的Method1當成一個虛方法來處理了

小結一下:

其實在本例中,如果開發者本意就是要讓B中的Method1產生與A中的Method1不一樣的處理結果,不管你加不加new,或者加new、override中的任何一個,運行結果都不變,僅僅只是在內部編譯時,override關鍵字使同名方法變成一個虛方法,但是其語義是不一樣的。

1.如果不加關鍵字,會讓代碼的可讀性變差,假設A,B封裝成一個程序集,然後交給另一個公司的程序員做二次開發,後面的程序員又弄一個C類繼承自B,那麼他在調用b.Method1時,會不會搞糊塗?(雖然編譯不會出錯)
2.加上new關鍵字以後,就明確告訴編譯器,B類中的Method1與A類中的Method1毫無瓜葛,大家各過各的橋,各走各的道兒.
3.加上override關鍵字以後,表示B類中的Method1基本上是認可A類中的Method1處理方式的,只是有可能覺得功能還需要再擴展或修改一下,並且也允許B的子類可以繼續擴展B中的Method1,同時C#規定只有virtual方法才能被override,所以在最終編譯時,B中的Method1也會被編譯成virtual方法,關於這一點,可以通過下面的代碼驗證:

class B : A   
     {  
         new public void Method1()   
         {  
             base.Method1();  
             Console.WriteLine("B.Method1-->new");  
         }  
     }  
     class C : B   
     {  
         override public void Method1()   
         {  
             Console.WriteLine("C.Method1");  
         }  
     }

如果想讓C類繼續重寫(擴展)B中的Method1方法,這樣是無法通過編譯的,會提示:只有加了virtual,abstract,override關鍵字的方法,才能被override!這時只能把B中Method1前面的new換成override再來看看abstract方法與virtual方法的異同:

看一段代碼

abstract class A   
{  
     public virtual void VirtualMethod() {  
         Console.WriteLine("A.VirtualMethod1");  
     }  
     public abstract void AbstractMethod();  
}

首先:abstract方法只能出現在abstract類中,即只要某個類的定義中有抽象方法,那麼該類也必須是抽象類

其次:virtual可以有方法體的實現代碼,而abstract只能定義方法簽名(即:abstract跟接口中的方法一樣,只定義方法,不實現方法)

在c#編譯器內部,abstract方法也是當作virtual方法來處理的,只不過另外標註了abstract關鍵字

上圖中,可以看到AbstractMethod也被標記爲virtual方法,另外在子類繼承時,這二者也有一些區別,見下面的代碼:

class B : A   
     {  
        public void VirtualMethod()   
         {  
         }  
        ////或  
         //override public void VirtualMethod()  
         //{  
         //}  
         ////或  
        //new public void VirtualMethod()  
         //{  
         //}  
         public override void AbstractMethod()  
         {  
         }  
     }

即:父類中的abstract方法,子類必須實現,且必須用override關鍵字標註;而父類中的virtual方法,子類可以重新定義(即new),也可以重載(override),也可以不管(即不定義與父母virtual方法同名的方法)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章