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

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

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

  讓咱們經過實例來看一下這二者有什麼相同與不一樣之處。學習

 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的共同點:spa

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

    例如:code

 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方法。blog

  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方法。  事實上,當子類繼承父類的時候,父類中全部方法、字段(包括私有的)都會複製一份放在子類中。而咱們所謂的重寫和覆蓋,重寫、覆蓋的是存放在子類中的,複製出來的方法,而不是父類中的方法,因此固然不會對父類產生任何影響。而不能調用私有的、或者被重寫的方法或字段,是因爲無權訪問,而不是內存中不存在。

相關文章
相關標籤/搜索