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

为什么要在C#中显式重写虚拟方法?,c#,.net,inheritance,virtual,C#,.net,Inheritance,Virtual,为什么要在C#?中显式重写虚拟方法,因为它使代码更具可读性: class Derived : Base { void Foo(); } 在C++中,FoO可能是也可能不是虚拟方法,我们不能通过查看定义来判断。在C#中,我们知道一个方法是虚的(或不是虚的),因为存在虚关键字或override关键字 杰森下面的评论是一个更好的答案 (为清晰起见进行了编辑)通过将方法声明为virtual,您表示可以在派生类中重写该方法 通过将实现方法声明为override,表示您打算重写virtual方法

为什么要在C#?

中显式重写虚拟方法,因为它使代码更具可读性:

class Derived : Base
{
    void Foo();
}
在C++中,FoO可能是也可能不是虚拟方法,我们不能通过查看定义来判断。在C#中,我们知道一个方法是虚的(或不是虚的),因为存在虚关键字或override关键字

杰森下面的评论是一个更好的答案


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

通过将方法声明为
virtual
,您表示可以在派生类中重写该方法

通过将实现方法声明为
override
,表示您打算重写
virtual
方法


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

如果您不添加
override
关键字,该方法将被隐藏(好像它有
新的
关键字),而不是被覆盖

例如:

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++方法在C++中这样做。()

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

这是因为C语言团队成员都是熟练的C++程序员。并了解此特定错误的早期程度:

class Base {
protected:
    virtual void Mumble(int arg) {}
};

class Derived : public Base {
protected:
    // Override base class method
    void Mumble(long arg) {}
};
这比你想象的要普遍得多。派生类始终在另一个源代码文件中声明。通常情况下,你不会马上就搞错,它发生在你重构的时候。没有来自编译器的窥视,代码运行非常正常,只是没有达到您期望的效果。你可以看一个小时或一天,却看不到bug

这在C#程序中永远不会发生。即使是管理C++也采用了这种语法,有意地用本机C++语法打破。总是一个勇敢的选择。IntelliSense去掉了多余的赘言

C#中有很多类似于这种避免bug语法的语法调整



<>编辑:其余C++社区同意并采用覆盖关键字到新的C++ 11语言规范中。它让Intellisense能够帮助我们重写一个方法。输入“override”,Intellisense弹出一个选项,甚至为我们填充整个方法签名。这有多棒?…而且,最重要的是,它允许编译器在我们出错时告诉我们(例如,如果在C++中向基类方法中添加参数,它会中断所有派生类,但是您无法知道它——这是一些非常讨厌的bug的原因,因为派生类行为的位只是悄悄地停止工作。在C语言中,对于每个重写都不再覆盖任何内容的错误给出了一个错误)。“在C++中,我们可能无法通过查看定义来判断。"——通过查看定义,我们可以知道它不是C++。@ StAXX:你听到的嗖嗖声是你错过了点。我说这个答案是错误的,因为添加<代码>覆盖> <代码>使代码的行为完全不同。@乔治:因为你只能在抽象类中使用抽象修饰符。@ George Stocker -因为你可能不会。要将整个类标记为抽象类(该类需要抽象修饰符才能有抽象方法)。不需要使用
override
关键字–请参见我的答案。@SLaks:如果您要重写,则可以。(将我的注释复制到此处,因为这是一个重要的问题。我想应该将其作为答案:-)…重写还允许编译器在我们出错时告诉我们(例如,如果在C++中向基类方法中添加参数,它会中断所有派生类,但是您无法知道它——这是一些非常讨厌的bug的原因,因为派生类行为的位只是悄悄地停止工作。在C语言中,对于每个重写都不再覆盖任何内容的错误给出了一个错误)。我同意这不应该是合法的,应该抛出一个错误而不是警告。(编辑:有人删除了他在这上面的评论。)+1最佳答案IMO,因为它解释了语言设计决策背后的“为什么”,而不是“虚拟呼叫如何工作”正如评分更高的答案一样……PS.@Hans,这些天我似乎碰到了很多你写的相关答案:)