`

我们为什么需要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关键字使用详解

    在使用override关键字时,需要注意的是,派生类中重写的函数必须与基类中的函数具有相同的名称、返回类型和参数列表。例如: ```cpp class Person { public: virtual void Eat() const = 0; }; class Student : ...

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

    - **Override**: 当一个派生类需要修改或扩展从基类继承的方法的行为时,可以使用 `override` 关键字。这要求基类的方法必须是 `virtual` 或 `abstract` 的。 - **New**: 当一个派生类希望保留基类的行为同时添加...

    override abstract virtual interface比较

    在 C# 编程语言中,override、abstract、virtual、interface 是四个关键字,它们之间存在着紧密的联系,我们经常会遇到 override、abstract、virtual 这三个关键字的使用,而 interface 则是一种特殊的抽象类。...

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

    C# 中的 new、abstract、virtual、override、sealed 关键字的区别和使用代码示例 摘要:本资源旨在对 C# 中的 new、abstract、virtual、override、sealed 关键字进行详细的解释和比较,并提供实践代码示例,以帮助...

    Delphi面向对象:overload与override[文].pdf

    在基类中,我们定义了一个虚拟方法DoSomething,而在派生类中,我们使用override关键字来重写这个方法。 override的好处是允许开发者在派生类中添加新的功能,而不影响父类的原有功能。同时,override也可以帮助...

    opreator-override.zip_override+c++_运算符重载

    Derived operator+(const Derived& other) const override { // 使用override关键字 // 实现Derived类的加法逻辑 } }; ``` 在这个例子中,`Derived::operator+`重写了`Base::operator+`,并提供了针对`Derived`...

    C++关键字汇总 需要的可以下

    首先,我们要明白C++的关键字是用来控制程序流程、声明数据类型、创建类和对象、处理异常等核心功能的。例如: 1. 数据类型关键字:`int`, `char`, `float`, `double` 用于声明不同类型的变量,如整型、字符型、...

    new,override,virtual 示例

    `override` 关键字用于重写基类中被声明为`virtual`的方法。这意味着,即使通过基类的引用调用该方法,实际上执行的是派生类中的实现。这使得多态性成为可能,即同一个方法调用可以根据对象的实际类型产生不同的...

    New与Override重写的区别例子.txt

    - `new` 关键字不需要基类方法声明为 virtual。 - `override` 关键字要求基类方法必须声明为 virtual 或 abstract。 3. **语义差异:** - `new` 关键字主要用来隐藏基类的方法,以便在派生类中提供不同的实现。 ...

    C#的关键字大全

    * virtual:虚方法的关键字,不含方法实现,用 override 对其实现。 语句关键字 语句是程序指令。除了下表中引用的主题中介绍的以外,语句都是按照顺序执行的。 * 选择语句:if、else、switch、case * 迭代语句:...

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

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

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

    如果一个方法被声明为 `virtual`,那么在派生类中可以通过 `override` 关键字重写它。`virtual` 关键字不能与 `static`、`abstract`、`private` 或 `override` 关键字结合使用,因为它们代表不同的概念。`virtual` ...

    c# override new base 关系

    首先,我们来看 `override` 关键字。`override` 用于重写基类中的虚方法(virtual method)。当你在派生类中使用 `override` 关键字修饰一个方法时,这个方法将覆盖基类中相同签名的虚方法。这样做使得派生类可以...

    C# 关键字word版

    它们在非抽象派生类中必须被重写(`override`),否则派生类也必须声明为抽象的。使用`abstract`修饰符声明的方法默认是`virtual`的,这意味着它们可以被派生类覆盖。同时,尝试在抽象方法声明中使用`static`或`...

    Android ArrayList关键字查询.rar

    为了实现关键字查询,我们需要对ArrayList中的每个对象进行遍历,检查其属性(如名称、描述等)是否包含查询关键字。 1. **创建关键词查询函数**: 你可以创建一个方法,接受ArrayList和查询关键字作为参数,返回...

    Delphi 关键字详解

    13. **Virtual** 和 **Override**:虚拟方法可以在子类中重写,而override关键字确保子类的方法确实重写了父类的方法。 14. **Static**:静态成员属于类本身,而不是类的实例。 15. **Private**,**Protected**,*...

    base关键字的使用

    通过以上介绍,我们可以看到`base`关键字在C#中的重要作用。它不仅可以用于调用基类的构造函数,还可以用于访问基类的方法和属性。合理利用`base`关键字可以增强代码的复用性和可维护性,是每个C#程序员都应该掌握的...

Global site tag (gtag.js) - Google Analytics