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