• C#中的三个关键词new , virtual , override的区别


    C#支持单继承,说到继承就不得不说newvirtualoverride这三个关键词,灵活正确的使用这三个关键词,可以使程序结构更加清晰,代码重用性更高。
    以下是msdn中对newvirtualoverride的定义:
            使用 new修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new修饰符修饰它。
             virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。
    调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。默认情况下,方法是非虚拟的。不能重写非虚方法。
    不能将 virtual 修饰符与以下修饰符一起使用:
    static     abstract     override
            使用 override 修饰符来修改方法、属性、索引器或事件。重写方法提供从基类继承的成员的新实现。由重写声明重写的方法称为重写基方法。重写基方法必须与重写方法具有相同的签名。
    不能重写非虚方法或静态方法。重写基方法必须是虚拟的、抽象的或重写的。
    重写声明不能更改虚方法的可访问性。重写方法和虚方法必须具有相同的访问级修饰符。
    不能使用下列修饰符修改重写方法:
    new    static     virtual    abstract
    重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且重写属性必须是虚拟的、抽象的或重写的。
            上面的描述都很抽象,对于初学者可能不好理解,下面我将用示例来说明这三个用法和区别:此程序在vs2005下调试通过。其中有三个类,分别为基类BaseClass,继承类InheritClass和继承类的继承类GrandsonClass代码分别如下:
    BaseClass.cs
    namespace NewVirtualOverride
    {
        class BaseClass
         {
            public BaseClass()
             {
             }
            public void Print()
             {
                Console.WriteLine("BaseClassPrint");
             }
         }
    }
    InheritClass.cs
    namespace NewVirtualOverride
    {
        class InheritClass : BaseClass
         {
            public InheritClass():base()
             {
             }
            public void Print()
             {
                Console.WriteLine("InheritClassPrint");
             }
         }
    }
    GrandsonClass.cs
    namespace NewVirtualOverride
    {
        class GrandsonClass : InheritClass
         {
            public GrandsonClass():base()
             {
             }
            public void Print()
             {
                Console.WriteLine("GrandsonClassPrint");
             }
         }
    }
    最后是主程序Program:
    namespace NewVirtualOverride
    {
        class Program
         {
            static void Main(string[] args)
             {
                BaseClass baseclass = new BaseClass();
                 baseclass.Print();
                InheritClass inheritClass = new InheritClass();
                 inheritClass.Print();
                Console.ReadLine();
             }
         }
    }
    运行这个程序会得到如下的结果:
    BaseClassPrint
    InheritClassPrint
    其实细心的朋友在编译这个项目时,会发现出现了如下的警告提示:
    大致意思是说,基类和继承类中有相同名字的方法,请在继承类中使用new来重新定义方法。这里的微妙之处在于,无论我们是隐式地指定new方法,还是显式的指定,new方法都与基类中的方法无关,在名称、原型、返回类型和访问修饰符方面都无关。
    我们将程序中的Print()方法都变成new public void Print()后,上面的异常就不会发生了。再次运行程序,结果不变。new就是继承类使用与基类方法相同的名字对基类方法的重写。
    下面我们看看virtual override的搭配使用方法。
    BaseClass.cs改变如下:public virtual void Print();
    InheritClass.cs改变如下:public override void Print();
    运行程序,结果如下:
    BaseClassPrint
    InheritClassPrint
         虽然结果与用new修饰符差不多,,但是其中的含意可不同,new是继承类对基类方法的重写而在继承类中产生新的方法,这时基类方法和继承方法之间没有任何的关系了,可是override就不同了,它也是对基类中方法的重写,但此时只是继承类重写了一次基类的方法。可以参考下面的例子来加深理解。
    Program.cs改变如下:
    BaseClass baseclass = new BaseClass();
    baseclass.Print();
    InheritClass inheritClass = new InheritClass();
    inheritClass.Print();
    BaseClass bc = new InheritClass();
    bc.Print();
    分别运行用new修饰和用virtual/override修饰的程序,其结果如下:
    new修饰的结果
    BaseClassPrint
    InheritClassPrint
    BaseClassPrint
    virtual/override修饰的结果:
    BaseClassPrint
    InheritClassPrint
    InheritClassPrint
       从上面的结果可以看出,在用new修饰的情况下,虽然bc是用InheritClass创建的实例,但是bc.Print()打印的还是BaseClassPrint,因为此时BaseClassInheritClass中的Print已经是互不相同没有关系的两个方法了,而在virtual/override修饰的情况下,bc调用的Print方法已经被其子类override了,所以就打印了InheritClassPrint
        最后我们再说说关键词之间的搭配关系,上面已经给出了virtualoverride不兼容的几个关键词,这里就不重复了。我要说的是newvirtual在声明函数时,其实可以一块使用。因为这个函数是新的,故与其它任何new函数一样,隐藏了具有相同原型的继承来的函数。因为这个函数也是虚拟的,所以可以在派生类中进一步复位义,这样就为这个虚拟函数建立了一个新的基级别。最后用GrandsonClass类来看看。
    GrandsonClass.cs修改如下:
    namespace NewVirtualOverride
    {
        class GrandsonClass : InheritClass
         {
            public GrandsonClass():base()
             {
             }
            public override void Print()
             {
                Console.WriteLine("GrandsonClassPrint");
             }
         }
    }
    InheritClass.cs修改如下:
    namespace NewVirtualOverride
    {
        class InheritClass : BaseClass
         {
            public InheritClass():base()
             {
             }
            new public virtual void Print()
             {
                Console.WriteLine("InheritClassPrint");
             }
         }
    }
    BaseClass.cs修改如下:
    namespace NewVirtualOverride
    {
        class BaseClass
         {
            public BaseClass()
             {
             }
            public virtual void Print()
             {
                Console.WriteLine("BaseClassPrint");
             }
         }
    }
    Program.cs修改如下:
    namespace NewVirtualOverride
    {
        class Program
         {
            static void Main(string[] args)
             {
                BaseClass baseclass = new BaseClass();
                 baseclass.Print();
                InheritClass inheritClass = new InheritClass();
                 inheritClass.Print();
                BaseClass grandsonClass = new GrandsonClass();
                 grandsonClass.Print();\
                Console.ReadLine();
             }
         }
    }
    运行结果为:
    BaseClassPrint
    InheritClassPrint
    BaseClassPrint
    可见在InheritClass中使用了new以后,就意味着它与基类的同名方法为两个不同方法了,而它又是虚拟的,所以它的子类还可以继续继承BaseClassPrint()方法。
            将函数声明为virtual 与将它声明为new virtual是一样的,因为new仍然是默认的。所以下面的两句是相同的:
    public new virtual void Print(); public virtual void Print();
    那么new virtual的意义又在什么地方呢?在大型的层次结构中,这可能很有用,比如如下的System.Windows.Form类的继承关系
    Object->MarshalByRefObject->Component->Control->ScrollableControl->
    ContainerControl
    很容易想象出将一个派生的窗体集合作为窗体对待,而不是作为Object的情形。
    再将Program.cs修改如下:
    namespace NewVirtualOverride
    {
        class Program
         {
            static void Main(string[] args)
             {
               BaseClass baseclass = new BaseClass();
                 baseclass.Print();
                InheritClass inheritClass = new InheritClass();
                 inheritClass.Print();
                BaseClass grandsonClass1 = new InheritClass();
                 grandsonClass1.Print();
                InheritClass grandsonClass2 = new GrandsonClass();
                 grandsonClass2.Print();
                Console.ReadLine();
             }
         }
    }
    运行结果为
    BaseClassPrint
    InheritClassPrint
    BaseClassPrint
    GrandsonClassPrint
    举例:
    using System;
    class A
    {
      public virtual void F(){Console.WriteLine("A.F");}
    }
    class B:A
    {
      public override void F(){Console.WriteLine("B.F");}
    }
    class C:B
    {
       new public virtual void F(){Console.WriteLine("C.F");}
    }
    class D:C
    {
      public override void F(){Console.WriteLine("D.F");}
    }
    class Test
    {
      static void Main()
      {
         D d = new D();
         A a =d;
         B b =d;
         C c =d;
         a.F();
         b.F();
         c.F();
         d.F();
      }
    }
    输出结果为 B.F 
               B.F
               D.F
               D.F
     


       本人博客的文章大部分来自网络转载,因为时间的关系,没有写明转载出处和作者。所以在些郑重的说明:文章只限交流,版权归作者。谢谢

  • 相关阅读:
    题解-AtCoder ARC-083F Collecting Balls
    题解-CTS2019氪金手游
    题解-CTS2019随机立方体
    题解-APIO2019路灯
    题解-APIO2019桥梁
    vue-property-decorator 源码阅读
    如何在Vue项目中使用TypeScript
    在 Vue+TypeScript 项目中,如何配置 ESLint 和 Prettier
    JavaScript 原型和原型链
    pre-commit + imagemin 实现图片自动压缩
  • 原文地址:https://www.cnblogs.com/wzg0319/p/1430573.html
Copyright © 2020-2023  润新知