【问题标题】:WHy should virtual methods be explicitly overridden in C#?为什么要在 C# 中显式覆盖虚拟方法?
【发布时间】:2011-03-15 23:52:56
【问题描述】:

为什么要在 C# 中显式重写虚方法?

【问题讨论】:

    标签: c# .net inheritance virtual


    【解决方案1】:

    通过将方法声明为virtual,您表明您的意图该方法可以在派生类中被覆盖。

    通过将您的实现方法声明为override,您表明您的意图您正在覆盖virtual 方法。

    通过要求使用 override 关键字来覆盖虚拟方法,语言的设计者通过要求您陈述自己的意图来鼓励清晰。

    【讨论】:

    • @George:因为你只能在抽象类中使用抽象修饰符。
    • @George Stocker - 因为您可能不想将整个类标记为抽象类(该类需要抽象修饰符才能具有抽象方法)。
    • override 关键字不是必需的 - 请参阅我的答案。
    • @SLaks:如果你想覆盖它
    • (在这里复制了我的评论,因为这是一个重要的观点。我猜应该让它成为一个答案:-) ...覆盖还允许编译器在我们犯错时告诉我们(例如如果您在 C++ 中向基类方法添加一个参数,它会破坏所有派生类,但您无法知道它 - 这是一些非常讨厌跟踪错误的原因,因为派生类行为的某些部分只是悄悄地停止工作。在 C# 中,它会为不再覆盖任何内容的每个覆盖提供错误)
    【解决方案2】:

    如果您不添加 override 关键字,该方法将被隐藏(就像它具有 new 关键字一样),不会被覆盖。

    例如:

    class Base {
        public virtual void T() { Console.WriteLine("Base"); }
    }
    class Derived : Base {
        public void T() { Console.WriteLine("Derived"); }
    }
    
    Base d = new Derived();
    d.T();
    

    此代码打印Base。 如果将override 添加到Derived 实现中,代码将打印Derived

    您不能在 C++ 中使用虚方法执行此操作。 (There is no way to hide a C++ virtual method without overriding it)

    【讨论】:

    • 我同意这不合法,应该抛出错误而不是警告。 (编辑:有人删除了他上面的评论)。
    【解决方案3】:

    这是因为 C# 团队成员都是熟练的 C++ 程序员。并且知道这个特定的错误有多早:

    class Base {
    protected:
        virtual void Mumble(int arg) {}
    };
    
    class Derived : public Base {
    protected:
        // Override base class method
        void Mumble(long arg) {}
    };
    

    它比您想象的要普遍得多。派生类总是在另一个源代码文件中声明。您通常不会立即出错,它会在您重构时发生。编译器没有窥探,代码运行非常正常,只是没有按照您的预期执行。你可以看一个小时或一天而看不到错误。

    这在 C# 程序中永远不会发生。甚至托管 C++ 也采用了这种语法,故意打破了原生 C++ 语法。永远是勇敢的选择。 IntelliSense 消除了多余的冗词。

    在 C# 中有很多类似于这种避免错误的语法的语法调整。


    编辑:C++ 社区的其他成员同意并将 override 关键字纳入新的 C++11 语言规范。

    【讨论】:

    • +1 最佳答案 IMO,因为它解释了语言设计决策背后的“原因”,而不是“虚拟呼叫如何工作”,因为评分较高的答案... PS。 @Hans 这些天我似乎遇到了很多你写的相关答案:)
    【解决方案4】:

    因为它使代码更具可读性:

    class Derived : Base
    {
        void Foo();
    }
    

    在 C++ 中,Foo 可能是也可能不是虚拟方法,我们无法通过查看定义来判断。在 C# 中,我们知道一个方法是虚拟的(或不是),因为有一个 virtual 或 override 关键字。

    Jason 下面的评论是一个更好的答案。

    (为清楚起见进行了编辑)

    【讨论】:

    • ... 它使 Intellisense 能够帮助我们覆盖方法。键入“覆盖”,Intellisense 会弹出一个选项,甚至为我们填写整个方法签名。这有多棒?
    • ...而且,最重要的是,它允许编译器在我们犯错时告诉我们(例如,如果您在 C++ 中向基类方法添加参数,它会破坏所有派生类,但你无法知道它 - 这是一些非常讨厌跟踪错误的原因,因为派生类行为的某些部分只是悄悄地停止工作。在 C# 中,它会为不再覆盖任何内容的每个覆盖提供错误)
    • “在 C++ 中可能是这样,我们无法通过查看定义来判断。” -- 通过查看定义,我们可以判断它不是 C++全部。
    • @stakx:你听到的嗖嗖声是你没抓住重点。
    • 我说这个答案是错误的,因为添加 override 会使代码的行为完全不同。
    【解决方案5】:

    不是所有的虚方法都应该被覆盖,尽管所有的抽象方法都应该(并且必须)被覆盖。至于为什么“覆盖”关键字是显式的,那是因为覆盖和隐藏的行为不同。隐藏方法不是通过对基类的引用来调用的,而重写方法是。这就是为什么编译器会特别警告您在隐藏而不是覆盖的情况下应如何使用“new”关键字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 2018-01-28
      • 1970-01-01
      • 2013-01-15
      • 2020-04-01
      • 1970-01-01
      相关资源
      最近更新 更多