zoukankan      html  css  js  c++  java
  • 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方法。
      事实上,当子类继承父类的时候,父类中所有方法、字段(包括私有的)都会复制一份放在子类中。而我们所谓的重写和覆盖,重写、覆盖的是存放在子类中的,复制出来的方法,而不是父类中的方法,所以当然不会对父类产生任何影响。而不能调用私有的、或者被重写的方法或字段,是由于无权访问,而不是内存中不存在。

  • 相关阅读:
    48. Rotate Image
    47. Permutations II
    46. Permutations
    45. Jump Game II
    44. Wildcard Matching
    43. Multiply Strings
    42. Trapping Rain Water
    41. First Missing Positive
    40. Combination Sum II
    39. Combination Sum
  • 原文地址:https://www.cnblogs.com/vsSure/p/7816639.html
Copyright © 2011-2022 走看看