C#design:为什么抽象方法需要new / override,虚拟方法不需要?

时间:2010-09-03 09:37:48

标签: c# virtual language-design abstract-methods

为什么抽象方法需要new / override,虚拟方法不需要?

样本1:

abstract class ShapesClass
{
    abstract public int Area(); // abstract!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // Error: missing 'override' or 'new'
    {
        return x * y;
    }
}

编译器将显示以下错误: 要使当前成员覆盖该实现,请添加override关键字。否则添加新关键字

样本2:

class ShapesClass
{
    virtual public int Area() { return 0; } // it is virtual now!
}

class Square : ShapesClass
{
    int x, y;

    public int Area() // no explicit 'override' or 'new' required
    {
        return x * y;
    }
}

通过默认隐藏方法,这将编译正常。

我完全理解技术差异。但我想知道为什么语言是这样设计的。 “样本2”中的限制也不是更好吗?我的意思是在大多数情况下,如果你创建一个与父类同名的方法,你通常打算覆盖它。所以我认为明确说明Override / New对虚拟方法也有意义。

这种行为是否存在设计明智的原因?

更新 第二个样本实际上会引发警告。第一个示例显示错误,因为子类是实现抽象方法所必需的。我没有看到VS中的警告..现在对我来说非常有意义。感谢。

5 个答案:

答案 0 :(得分:11)

使用.NET 3.5 SP1中附带的C#3.0编译器或.NET 4.0中附带的C#4.0编译器,我得到以下错误作为您的第一个示例:

  

错误CS0534:'ConsoleApplication3.Square'未实现继承的抽象成员'ConsoleApplication3.ShapesClass.Area()'

以下警告第二个:

  

警告CS0114:'ConsoleApplication3.Square.Area()'隐藏继承的成员'ConsoleApplication3.ShapesClass.Area()'。要使当前成员覆盖该实现,请添加override关键字。否则添加新关键字。

在第一种情况下,这是一个错误,因为您实际上没有覆盖基本方法,这意味着在具体类中没有实现抽象方法。在第二种情况下,它是一个警告,因为代码在技术上是正确的,但编译器怀疑它不是你的意思。这是启用“将警告视为错误”编译设置通常是个好主意的原因之一。

所以我不能重复你的行为,编译器的行为对我来说是正确的。您使用的是哪个版本的编译器?

答案 1 :(得分:7)

以下是直接来自C#规范的答案。

  

...隐藏一个可访问的名称   继承范围会导致警告   报道。在示例中

class Base
{
    public void F() {}
}
class Derived: Base
{
    public void F() {}      // Warning, hiding an inherited name
}
  

衍生原因中的F声明   要报告的警告。隐藏一个   继承的名称特别不是   错误,因为那样会排除   基类的单独演变。   例如,上述情况可能会发生   因为后来才出现   Base的版本引入了F方法   这在早先没有出现过   该类的版本。有上述   情况是一个错误,然后任何   改变了对基类的改变   单独版本的类库   可能导致派生   类变为无效。警告   隐藏继承名称所造成的   通过使用新的消除   改性剂:

class Base
{
    public void F() {}
}
class Derived: Base
{
    new public void F() {}
}
  

新修饰符表示F   在Derived中是“新的”,它就是   确实打算隐藏继承   构件。

答案 2 :(得分:3)

不同之处在于必须重写抽象方法,但虚拟不会。

在没有实现所有抽象成员的情况下继承抽象类(在非抽象类中)是一个错误,但是在从类继承而没有指定overridenew时只会收到警告虚方法。

答案 3 :(得分:0)

我认为在第一种方式中你会遇到编译器错误,因为抽象方法是隐藏的而不是实现的(所以有效的你的类是错误的,并且很难找出原因)。在第二种情况下,您只得到一个警告,因为该类是可用的。

答案 4 :(得分:0)

版本

乍一看,您可能认为隐藏方法看起来并不特别有用。有一种情况 但是,您可能需要使用它。假设您要使用名为MotorVehicle的类 是由另一个程序员编写的,你想使用这个类来派生自己的类。进一步, 我们还假设您要在派生类中定义Accelerate()方法。例如:

public class Car : MotorVehicle
{
    // define the Accelerate() method
    public void Accelerate()
    {
        Console.WriteLine(“In Car Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

接下来,让我们假设其他程序员稍后修改MotorVehicle类并决定 添加自己的virtual Accelerate()方法:

public class MotorVehicle
{
    // define the Accelerate() method
    public virtual void Accelerate()
    {
        Console.WriteLine(“In MotorVehicle Accelerate() method”);
        Console.WriteLine(model + “ accelerating”);
    }
}

其他程序员添加此Accelerate()方法会导致出现问题: Accelerate()类中的Car方法隐藏了现在定义的继承Accelerate()方法 他们的MotorVehicle课程。稍后,当您编译Car类时,编译器不清楚 你是否真的希望你的方法隐藏继承的方法。因此, 当您尝试编译Car类时,编译器会报告以下警告:

  

警告CS0114:'Car.Accelerate()'隐藏继承的成员   “MotorVehicle.Accelerate()”。使当前成员覆盖该成员   实现,添加override关键字。否则添加新关键字。