【问题标题】:C# design: Why is new/override required on abstract methods but not on virtual methods?C# 设计:为什么抽象方法需要 new/override 而虚拟方法不需要?
【发布时间】:2011-04-07 18:21:46
【问题描述】:

为什么抽象方法需要 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.. 中的警告现在对我来说非常有意义。谢谢。

【问题讨论】:

  • 如果你是对的(还没来得及检查)那么它看起来像是编译器中的一个错误;我希望它在这两种情况下都会发出警告。您使用的是哪个版本的编译器?
  • 我不知道为什么你没有收到错误,但是在虚拟覆盖上需要覆盖或新的 IS,并且上面的示例无法编译。
  • 我收到一条警告:“警告 3 'Stackoverflow_Test.Square.Area()' 隐藏继承的成员 'Stackoverflow_Test.ShapesClass.Area()'。要使当前成员覆盖该实现,请添加覆盖关键字。否则添加新关键字。”
  • @Phil 您可能正在编译“将警告视为错误”。这不是编译错误,而是编译警告
  • @Rune 你说得对,我总是在编译时打开“警告为错误”而忘记其他人没有!

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


【解决方案1】:

使用 .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 关键字。否则添加新关键字。

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

所以我无法重现您的行为,而编译器的行为在我看来是正确的。您使用的是哪个版本的编译器?

【讨论】:

  • 绝对有道理,谢谢。好像我在这个项目中隐藏了警告,所以我没有看到这种行为。
【解决方案2】:

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

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

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

派生原因中 F 的声明 要报告的警告。隐藏一个 继承的名字特别不是 错误,因为这将排除 基类的单独演化。 例如,上述情况可能 之所以出现是因为后来 Base 版本引入了 F 方法 以前没有的 类的版本。有了以上 情况是一个错误,然后任何 对 a 中的基类所做的更改 单独版本化的类库 可能会导致衍生 类变得无效。警告 由隐藏继承的名称引起的 通过使用新的被淘汰 修饰符:

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

新的修饰符表示 F 在 Derived 中是“新的”,并且它是 确实打算隐藏继承的 会员。

【讨论】:

    【解决方案3】:

    不同之处在于抽象方法必须被覆盖,而虚拟方法则不需要。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        版本控制

        乍一看,您可能会认为方法隐藏似乎不是特别有用。有一种情况 但是,您可能需要在哪里使用它。假设你想使用一个名为 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()方法会导致一个问题: Car 类中的 Accelerate() 方法隐藏了现在定义的继承的 Accelerate() 方法 他们的MotorVehicle 班级。后来,当你来编译你的Car 类时,编译器并不清楚 您是否真的打算让您的方法隐藏继承的方法。正因为如此, 当您尝试编译 Car 类时,编译器会报告以下警告:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-03
          • 2020-05-18
          • 2020-09-02
          • 1970-01-01
          • 1970-01-01
          • 2020-04-13
          • 2012-01-26
          • 2015-07-10
          相关资源
          最近更新 更多