C#繼承中的override(重寫)與new(覆蓋)用法


  剛接觸C#編程,我也是被override與new搞得暈頭轉向。於是花了點時間翻資料,看博客,終於算小有領悟,把學習筆記記錄於此。

  首先聲明一個父類Animal類,與繼承Animal的兩個子類Dog類與Cat類。父類Animal中有一個Say方法,而子類Dog與Cat分別override(重寫)與new(覆蓋)了Say方法。

  讓我們通過實例來看一下這兩者有什么相同與不同之處。

 1 public class Animal  2  {  3 public virtual void Say()  4  {  5 Console.WriteLine("Hello,Animal");  6  }  7  }  8 public class Dog : Animal  9  { 10 public override void Say() 11  { 12 Console.WriteLine("Hello,Dog"); 13  } 14  } 15 public class Cat : Animal 16  { 17 public new void Say() 18  { 19 Console.WriteLine("Hello,Cat"); 20  } 21 }

首先說override與new的共同點:

  1. 都是子類在重新實現父類中簽名相同的方法時使用。
  2. 當聲明一個子類對象時,調用這個方法,調用的都是子類中實現的方法。

    例如:

 1 class Program  2  {  3 static void Main(string[] arge)  4  {  5 Dog d = new Dog();  6 Cat c = new Cat();  7  d.Say();//調用override的方法  8  c.Say();//調用new的方法  9  } 10 }

   輸出是:

Hello,Dog Hello,Cat 

    此時調用的分別是Dog與Cat類中實現的Say方法。

  3.都不會影響父類自身的方法。

   如:

1 class Program 2  { 3 static void Main(string[] arge) 4  { 5 Animal a = new Animal(); 6 a.Say();//調用父類方法。未受影響。 7  } 8 }

  此時的輸出是:

Hello,Animal 

 

下面說兩者的不同之處:

  1.

  (1)override:父類方法必須用virtual修飾,表示這個方法是虛方法,可以被重寫。否則不能被重寫。

  (2)new :   父類方法不必使用virtual修飾。

  2.

  (1)override : 使用override時,父類中必須存在簽名完全相同的virtual方法。否則編譯不通過。

    如果我在Dog類的Say增加一個string類型的形參,則編譯器會提示:沒有合適的方法可以重寫。

  (2)new :   使用new時,父類中最好存在簽名相同的方法。如果沒有,VS會有提示,但編譯不會報錯。此時,new關鍵字便沒有了意義。

   如果我在Cat類的Say增加一個string類型的形參,VS會提示:new關鍵字不是必須的。

  3.當子類中存在與父類方法簽名相同的方法,而沒有被override或new修飾時,默認為new。

  也就是說,override必須寫,而new可以不寫(不推薦)。

  4.這是最重要的一點。以上三點都是使用方法的區別,而這一點是兩者在實際使用時效果的區別。

  (1)override :重寫后,當子類對象轉換為父類時,無法訪問被重寫的虛方法。也就是,被子類重寫后,虛方法在子類對象中便失效了。

   如:

class Program { static void Main(string[] arge) { Dog d = new Dog(); Animal a = d as Animal;//子類轉換為父類。注意此時a與d指向同一對象,但d是作為Dog類訪問,而a是作為Animal類訪問 d.Say();//此時調用的是override的方法 a.Say();//此時調用的也是override的方法  } }

    輸出為:

Hello,Dog Hello,Dog 

  兩次調用的都是Dog中重寫的Say方法

  (2)new : 覆蓋后,當子類對象轉換為父類,可以訪問被覆蓋的父類方法。也就是,轉換為父類后,子類new的方法便失效了,此時調用的是父類方法。
       當其再轉換為子類時,調用的又變為子類方法。

    如:

 1 class Program  2  {  3 static void Main(string[] arge)  4  {  5 Cat c = new Cat();  6 Animal a = c as Animal;//子類轉換為父類。注意此時a與c指向同一對象,但c是作為Cat類訪問,而a是作為Animal類訪問  7 c.Say();//此時調用的是new的方法  8 a.Say();//此時調用的是父類中的方法  9  } 10 }

   此時的輸出為:

Hello,Cat Hello,Animal 

內存原理:
  我們都知道,調用對象的方法,實際上是訪問對象方法在內存中的地址。那么既然可以通過c.Say()訪問到父類的方法,說明在對象c中,也有Animal類的Say方法。
  事實上,當子類繼承父類的時候,父類中所有方法、字段(包括私有的)都會復制一份放在子類中。而我們所謂的重寫和覆蓋,重寫、覆蓋的是存放在子類中的,復制出來的方法,而不是父類中的方法,所以當然不會對父類產生任何影響。而不能調用私有的、或者被重寫的方法或字段,是由於無權訪問,而不是內存中不存在。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM