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

  • 相关阅读:
    extjs4 数据实体模型
    WPF实现MDI窗体的方法
    WPF中图形表示语法详解(Path之Data属性语法
    Wpf DataGrid 数据绑定 排序 删除
    WPF: 使用TestApi模拟用户输入
    extjs4 事件处理
    WPF触发器
    XPath语法 在C#中使用XPath示例
    WPF 4 中DataGrid的模板列做双向数据绑定
    extjs4 标准面板
  • 原文地址:https://www.cnblogs.com/vsSure/p/7816639.html
Copyright © 2020-2023  润新知