zoukankan      html  css  js  c++  java
  • 谈谈C#中的三个关键词new , virtual , override(装载 Winner.Net)

    C#支持单继承,说到继承就不得不说new,virtual和override这三个关键词,灵活正确的使用这三个关键词,可以使程序结构更加清晰,代码重用性更高。 
       

          以下是msdn中对new,virtual和override的定义:
          使用 new 修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。
          virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。默认情况下,方法是非虚拟的。不能重写非虚方法。
          不能将virtual 修饰符与以下修饰符一起使用:
          static    abstract    override
          使用 override 修饰符来修改方法、属性、索引器或事件。重写方法提供从基类继承的成员的新实现。由重写声明重写的方法称为重写基方法。重写基方法必须与重写方法具有相同的签名。不能重写非虚方法或静态方法。重写基方法必须是虚拟的、抽象的或重写的。
          重写声明不能更改虚方法的可访问性。重写方法和虚方法必须具有相同的访问级修饰符。
        
          不能使用下列修饰符修改重写方法:
          new   static    virtual   abstract
          重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且重写属性必须是虚拟的、抽象的或重写的。 
          可以稍微归纳一下:
          1. 对于基类中说明为虚的方法则必须在派生类中new或者override(注:对于基类的虚方法,虽然你在派生类中即不new也不override,但系统还是会提示你添关键字。否则系统将视其为隐藏。我们的意思是一样的,但总觉得明明确确写上关键字还是好些)。
          2. 如果用基类指针指向派生类对象的方式,动态匹配的源动力是virtual,而new和override都会阻止这种向下寻求匹配的行为,所以要使虚函数的性质得已保持下去,就要隐藏基类的虚方法,即在派生类中隐藏基类虚方法时,同时加以virtual关键字,使在多层次继承中能够调用到对象自身的版本。
          3.在多层次继承中,三个关键字使用次序有限定,new没有使用前提,即不管是普通方法、虚方法还是重写了的方法。virtual的使用,在它的基类不能有函数签名相同的方法,否则系统将提示添加new,即隐藏基类中的方法。virtual一般只出现一次,除非要在子类中隐藏父类的虚方法。

          override的使用是为了重写基类虚方法。
         

      上面的描述都很抽象,对于初学者可能不好理解,下面我将用示例来说明这三个用法和区别:此程序在vs2005下调试通过。其中有三个类,分别

    为基类BaseClass,继承类InheritClass和继承类的继承类GrandsonClass代码分别如下:

      


    //BaseClass.cs
    namespace NewVirtualOverride
    {
    class BaseClass
    {
    public BaseClass()
    {
    }
    publicvoid Print()
    {
    Console.WriteLine("BaseClassPrint");
    }
    }
    }
    //InheritClass.cs
    namespace NewVirtualOverride
    {
    class InheritClass : BaseClass
    {
    public InheritClass():base()
    {
    }
    publicvoid Print()
    {
    Console.WriteLine("InheritClassPrint");
    }
    }
    }
    //GrandsonClass.cs
    namespace NewVirtualOverride
    {
    class GrandsonClass : InheritClass
    {
    public GrandsonClass():base()
    {
    }
    publicvoid Print()
    {
    Console.WriteLine("GrandsonClassPrint");
    }
    }
    }
    //最后是主程序Program:
    namespace NewVirtualOverride
    {
    class Program
    {
    staticvoid Main(string[] args)
    {
    BaseClass baseclass =new BaseClass();
    baseclass.Print();
    InheritClass inheritClass =new InheritClass();
    inheritClass.Print();
    Console.ReadLine();
    }
    }
    }
    运行这个程序会得到如下的结果:
    BaseClassPrint
    InheritClassPrint
     
    其实细心的朋友在编译这个项目时,会发现出现了如下的警告提示:

    class InheritClass:BaseClass
    {
    public InheritClass():base()
    {}

    //New Virtual Override InheritClass.Print()隐藏了继承的成员
    //New Virtual Override BaseClass.Print()。如果是刻意隐藏请使用new
    publicvoid Print()
    {
    Console.WriteLine("Hello");
    }
    }
       
         大致意思是说,基类和继承类中有相同名字的方法,请在继承类中使用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,因为此时BaseClass和InheritClass中的Print已经是互不相同没有关系的两个方法了,而在virtual/override修饰的情况下,bc调用的Print方法已经被其子类override了,所以就打印了InheritClassPrint。
     
     

     最后我们再说说关键词之间的搭配关系,上面已经给出了virtual和override不兼容的几个关键词,这里就不重复了。我要说的是new和virtual在声明函数时,其实可以一块使用。因为这个函数是新的,故与其它任何new函数一样,隐藏了具有相同原型的继承来的函数。因为这个函数也是虚拟的,所以可以在派生类中进一步复位义,这样就为这个虚拟函数建立了一个新的基级别。最后用GrandsonClass类来看看。


    将GrandsonClass.cs修改如下:
    namespace NewVirtualOverride
    {
    class GrandsonClass : InheritClass
    {
    public GrandsonClass():base()
    {
    }
    publicoverridevoid Print()
    {
    Console.WriteLine("GrandsonClassPrint");
    }
    }
    }
    InheritClass.cs修改如下:
    namespace NewVirtualOverride
    {
    class InheritClass : BaseClass
    {
    public InheritClass():base()
    {
    }
    newpublicvirtualvoid Print()
    {
    Console.WriteLine("InheritClassPrint");
    }
    }
    }
    BaseClass.cs修改如下:
    namespace NewVirtualOverride
    {
    class BaseClass
    {
    public BaseClass()
    {
    }
    publicvirtualvoid Print()
    {
    Console.WriteLine("BaseClassPrint");
    }
    }
    }
    Program.cs修改如下:
    namespace NewVirtualOverride
    {
    class Program
    {
    staticvoid 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以后,就意味着它与基类的同名方法为两个不同方法了,而它又是虚拟的,所以它的子类还可以继续继承BaseClass的Print()方法。
        将函数声明为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
    {
    staticvoid 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
  • 相关阅读:
    解析大型.NET ERP系统 权限模块设计与实现
    Enterprise Solution 开源项目资源汇总 Visual Studio Online 源代码托管 企业管理软件开发框架
    解析大型.NET ERP系统 单据编码功能实现
    解析大型.NET ERP系统 单据标准(新增,修改,删除,复制,打印)功能程序设计
    Windows 10 部署Enterprise Solution 5.5
    解析大型.NET ERP系统 设计异常处理模块
    解析大型.NET ERP系统 业务逻辑设计与实现
    解析大型.NET ERP系统 多国语言实现
    Enterprise Solution 管理软件开发框架流程实战
    解析大型.NET ERP系统 数据审计功能
  • 原文地址:https://www.cnblogs.com/zhcw/p/2565321.html
Copyright © 2011-2022 走看看