1. 程式人生 > >C#中的虛方法、抽象方法、抽象類、介面的聯絡與區別

C#中的虛方法、抽象方法、抽象類、介面的聯絡與區別

虛方法的關鍵字是virtual
抽象方法的關鍵字是abstract
重寫都是override 虛方法也可以new
虛方法和抽象方法的區別:
虛方法:可以在抽象類和非抽象類中定義,可以寫在父類中,在子類中可以被重寫,在定義虛方法時必須實現虛方法
(在定義虛方法時需要寫實現方法的程式碼或者至少要寫一個分號)

抽象方法:必須定義在抽象類中,必須寫在父類中,在子類中必須被重寫,在定義抽象方法時不能實現方法
(在定義抽象方法時不能有大括號和程式碼)
注:如果我們實現的這個功能它的一部分功能(輸出)要寫在父類中,而且在不同的子類中需要重寫,那麼在父類中的方法必須定義為虛方法,
否則,如果在父類中只需要指定有什麼功能,但不需要實現,這個時候我們就把父類中的方法定義為抽象方法。

說說抽象類的理解吧:
既然是抽象類,那麼就是對事物的抽象描述,它描述的是個體的共性。那馬這種動物來說,我們所說的馬就是一個抽象類。世界上存在很多種馬,白馬,黑馬,紅馬......如果沒有抽象的概念,我們就沒法獲得世界上所有馬,因為我們要說馬的時候,必須指定是哪種馬!但是我們其實是有抽象的概念的,我們定義了馬這樣的一個概念,用來指代世界上所有的馬。但馬在這個世界上並不是真實存在的,你所能看見的馬一定是某一種型別的馬!

所以說,抽象類就是這樣一種類,描述了一種事物的共性,它不能例項化,只能通過它的子類例項化。
抽象方法:抽象方法一定是抽象類裡面的,抽象的方法沒有主體,就是沒有實現程式碼,它的實現是由子類實現的。如果一個抽象類裡面全是抽象方法的畫,那麼這個類和介面的功能基本就是一致,而抽象類和介面不一樣的地方就在於抽象類可以有非抽象的方法。

virtual 關鍵字用於修飾方法、屬性、索引器或事件宣告,並使它們可以在派生類中被重寫。例如,此方法可被任何繼承它的類重寫。

標記為虛方法的方法,可以在子類被重寫。也就說子類可以變異。還是馬類為例:
public abstract class 馬類
{
//長毛這個方法是抽象的方法,因為它的實現
//必須是具體的那種馬去實現的
public abstract void 長毛();
//消化這個方法是虛方法,所有的馬
//都按這個方法去消化東西,也可以變異
public virtual void 消化()
{
Console.WriteLine("1小時消化1千克食物");
}
}
public class 紅馬 : 馬類

{
public override void 長毛()
{
Console.WriteLine("我長的是紅毛");
}
//在這裡變異了,消化能力超強
public override void 消化()
{
Console.WriteLine("1小時消化1噸食物");
}
}

在這裡要說明一點是隱藏與重寫的區別。

重寫:繼承時發生,在子類中重新定義父類中的方法,子類中的方法和父類的方法是一樣的

隱藏:在派生類中使用new宣告一個跟父類一樣的方法,那麼父類的方法將被隱藏起來,但是還是存在的,可以用base來呼叫。這樣相當於子類有兩套名稱一樣的方法。

public virtual void prinf() 

Console.WriteLine ("這是虛方法"); 


public override void prinf() 



Console.WriteLine ("這是新的方法"); 


public new void prinf() 

Console.WriteLine ("這是另一個新的方法"); 
 
 

 

下面的例子說明了C#虛擬方法與非虛方法的區別。

例子:


 
  1. using System;
  2. class A
  3. {
  4. public void F(){Console.WriteLine("A.F");}
  5. public virtual void G(){Console.WriteLine("A.G");}
  6. }
  7. class B:A
  8. {
  9. new public void F(){Console.WriteLine("B.F");}
  10. public override void G(){Console.WriteLine("B.G");}
  11. }
  12. class Test
  13. {
  14. static void Main()
  15. {
  16. B b=new B();
  17. A a=b;
  18. a.F();
  19. b.F();
  20. a.G();
  21. b.G();
  22. }
  23. }

例子中,A類提供了兩個方法:非虛的F和C#虛擬方法 G.類B則提供了一個新的非虛的方法F,從而覆蓋了繼承的F;類B同時還過載了繼承的方法G.那麼輸出應該是:

A.F

B.F

B.G

B.G

注意到本例中,方法a.G()實際呼叫了B.G,而不是A.G.這是因為編譯時值為A,但執行時值為B,所以B完成了對方法的實際呼叫。