zoukankan      html  css  js  c++  java
  • new , virtual , override

    可以稍微归纳一下:
          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()
    {
    }
    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
    其实细心的朋友在编译这个项目时,会发现出现了如下的警告提示:

    class InheritClass:BaseClass { public InheritClass():base() {} //New Virtual Override InheritClass.Print()隐藏了继承的成员 //New Virtual Override BaseClass.Print()。如果是刻意隐藏请使用new public void 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() { } 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以后,就意味着它与基类的同名方法为两个不同方法了,而它又是虚拟的,所以它的子类还可以继续继承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
    {
    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
  • 相关阅读:
    dinic模板
    ZOJ 3042 City Selection II 【序】【离散化】【数学】
    Codeforces 452D [模拟][贪心]
    Day25 python基础---面向对象进阶--模块与包
    Day22&23&24 python基础---面向对象进阶--常用模块
    Day21 python基础---面向对象进阶--内置方法
    Day19&20 python基础---面向对象进阶--装饰器函数,反射,内置方法
    Day18 python基础---面向对象三大特性---多态、封装
    Day17 python基础---面向对象三大特性---继承
    Day16 python基础---面向对象初识---组合
  • 原文地址:https://www.cnblogs.com/yidianfeng/p/1625760.html
Copyright © 2011-2022 走看看