`

我们为什么需要override关键字

阅读更多

        一直以来,我都觉得C#的继承体系结构太过繁琐,既要声明方法是否为virtual,又要使用new、override这样的关键字界定派生类方法在继承体系中的角色,远不如Java的继承实现来得简洁清爽。在Java当中,所有的类方法在默认情况下都是virtual的,所以就省下了将方法声明为virtual这个步骤。也许你会问,如果想声明一个非virtual的方法怎么办呢?所谓非virtual就是不允许继承了,那么在方法的签名中使用final关键字即可。从继承实现的最基本的虚方法声明中,我们可以看出两种语言在设计上不同的关注点:Java会认为基类方法在大部分情况会被覆写(override),而C#则相反。

        尽管C#的继承体系结构显得有些臃肿,但是,我也坚信存在即是真理,C#采用这样的方式实现继承也必然出于其它方面的考虑,至少当我知道C#是这样实现继承的时候,“严谨”一词就在我的脑海中不断闪现。不过,光是“严谨”这种感性的认识还不足以让我对C#的继承实现感到心悦诚服,毕竟作为程序员的我喜欢纯粹,也喜欢简约。于是乎,对C#继承体系结构的偏见就根深蒂固地扎根于我的认知土壤中了。直到最近在开发中碰到了一个问题,解决的过程让我明白到严谨是很重要的,不仅是程序员的态度,还有编程语言本身的支持。
      
        遇到的问题其实很简单,就是派生子类覆写了父类的一个方法,而该父类方法的参数发生了改变,编译器在编译过程中并没有发现这个问题。在程序运行的时候,则出现了死循环,并且没有任何的错误提示。这个bug着实让人很迷惑,也耗费了同事很多的时间,最后才发现是由于父类方法发生了改变,而子类中的覆写方法又没有更新造成的。请参见以下简化的代码:

public class ParentClass {
    
public int test(int i) {          
        
return i * 2;
    }

}


public class DerivedClass extends ParentClass {
    
public int test(int i) {
        
return i * 2 + 1;
    }

}


public class Test {
    
public static void main(String[] args) {
        ParentClass a 
= new DerivedClass();
        System.out.println(a.test(
0));    //输出结果为1
    }

}


接着,ParentClass的代码改为:

public class ParentClass {
    
public int test(int i, boolean flag) {          
        
if (flag) 
            
return i * 2;
        
else
            
return 0
    }

}


通过IDE的支持,我们可以找到使用test方法的地方,也就将main函数中的调用改为:System.out.println(a.test(0, true)); 虽然这样的改动并不会引发编译错误,在运行的时候也没有问题,但是很明显,输出结果变为了0,程序已经不再按照我们的意图而执行了,因为调用的是从父类继承过来的test方法,而不是我们原来所要求的调用覆写的方法了。像这样的bug是很难被发现的,如果不是因为程序在运行过程中出现了死循环,都不知道这个潜在的bug会在什么时候突然爆发。

        以上给出的例子已经很好的说明了C#使用override关键字的必要性。对应着C#,以上代码的DerivedClass中的test方法就要被声明为override,一旦ParentClass中的test方法发生了改变,编译器就会在编译过程发现这个错误。可见语言定义的严谨还是能够在很大程度上帮助程序员在开发中少犯错的。事实上,Java也意识到了这个方面的不足,也在语言定义上作了改进:通过使用内建的Override注释(Annotation)来避免以上提到的问题(参见参考文章[1])。个人觉得,Java的解决方案似乎更加优美,因为它是通过提供一个机制实现了继承上的制约,而非增加关键字。


         参考文章:[1] 在Eclipse 3.1中体验J2SE 5.0的新特性 : 第二部分 :注释类型 
                         [2] 了解何时使用 Override 和 New 关键字(C# 编程指南)  
                         [3] 使用 Override 和 New 关键字进行版本控制(C# 编程指南)

分享到:
评论

相关推荐

    C++ override关键字使用详解

    主要介绍了C++ override关键字使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    了解何时使用 Override 和 New 关键字(C# 编程指南)

    了解何时使用 Override 和 New 关键字(C# 编程指南)

    C#中Override关键字和New关键字的用法详解

    C# 语言经过专门设计,以便不同库中的基类与派生类... 如果派生类中的方法前面没有 new 或 override 关键字,则编译器将发出警告,该方法将有如存在 new 关键字一样执行操作。 如果派生类中的方法前面带有 new 关键

    new、abstract、virtual、override,sealed关键字区别和使用代码示例

    new、abstract、virtual、override,sealed关键字区别和使用代码示例

    override-linting-rule:TypeScript linting规则强制标记方法和属性覆盖

    如果要为Web构建,则需要在代码中定义替代装饰器。 该实现可以是一个空函数,不需要执行任何操作。 function override ( target : Object , propertyKey : string | symbol , descriptor ?: any ) : any | void { ...

    Delphi 关键字详解

    //Abstract关键字必须与Virtual或Dynamic关键字同时使用, 因为抽象方法必须被覆盖式实现. //抽象类不能实例化, 抽象方法不能包含方法体. type TDemo = class private protected procedure X; virtual; abstract;...

    深入理解C#中new、override、virtual关键字的区别

    下面小编就为大家带来一篇深入理解C#中new、override、virtual关键字的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    详解C++成员函数的override和final说明符的用法

    可使用 override 关键字来指定在基类中重写虚函数的成员函数。 语法 function-declaration override; 备注 override 仅在成员函数声明之后使用时才是区分上下文的且具有特殊含义;否则,它不是保留的关键字。 使用...

    C#几种关键字用法总结.zip

    C# 不安全代码关键字:unsafe、C# 关键字const 和 readonly、C# 关键字extern用法、C#关键字Fixed、C#关键字IntPtr、C#关键字之override详解、C#中DllImport用法汇总、C#中的IntPtr

    Java中的final关键字详解及实例

    用final关键字修饰的方法是不能被该类的子类override(重写),因此,如果在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。 注:类的private方法会隐式地被指定为final方法。 public class ...

    C#中方法的重写

    本文为您介绍C#中方法的...重写父类的方法要用到override关键字(具有override关键字修饰的方法是对父类中同名方  法的新实现);  b.要重写父类的方法,前提是父类中该要被重写的方法必须声明为virtual或者是abstract

    对话框VC源代码:override_fontdlg

    对话框源代码:override_fontdlg 关键字:override_fontdlg,对话框

    C#教材及new关键字、委托事件理解

    1、C#系列教程 2、C#中new和override 3、C#中的try-catch语句使用方法 4、C#的各种连接数据库 5、c#中的委托和实践 6、C#的New关键字的几种用法

    TOMO-CAT#CppNote#override和final1

    C++11关键字:override和final场景在传统C++中,经常容易发现意外重载虚函数的事情:struct SubClass: Base {有下列三种非预

    C++11 (智能指针、关键字、类型推导、新特性)

    c++11 面试题总结 1. 左值引用与右值引用的区别?右值引用的意义? 2. c++11 的智能指针种类以及使用场景...3. c++11 override,final关键字的作用? 4. c++11 类型推导 5. c++11 用过哪些新特性? (C++后台开发教程)

    sealed 修饰符是干什么的?

    sealed 修饰符表示密封用于类时,表示该类不能再被继承,不能和 abstract 同时使用,因为这两个修饰符在含义上互相排斥用于方法和属性时,表示该方法或属性不能再被重写,必须和 override 关键字一起使用,

    基于多态之虚方法、抽象类、接口详解

    如果需要重写,在子类方法的返回值前加 override 关键字。 4、子类在重写虚方法时,可以根据需求选择性的是否使用 base 关键字调用父类中的该方法。 虚方法语法格式如下: public class Father { public virtual ...

Global site tag (gtag.js) - Google Analytics