对C#中的“覆盖”与“新”感到困惑

我有以下课程:

class Base { public virtual void Print() { Console.WriteLine("Base"); } } class Der1 : Base { public new virtual void Print() { Console.WriteLine("Der1"); } } class Der2 : Der1 { public override void Print() { Console.WriteLine("Der2"); } } 

这是我的主要方法:

 Base b = new Der2(); Der1 d1 = new Der2(); Der2 d2 = new Der2(); b.Print(); d1.Print(); d2.Print(); 

输出为BaseDer2Der2

据我所知,即使指针指向它们,Override也不会让以前的方法运行。 所以第一行也应该输出Der2 。 然而Base出来了。

这怎么可能? 覆盖如何在那里不起作用?

你从来没有真正覆盖Print()Base版本。 您只在Der1使用单独的虚拟方法(名称相同)隐藏它。

当您在方法签名上使用new关键字时 – 您告诉编译器这是一个碰巧与您的某个基类的方法同名的方法 – 但没有其他关系。 您可以将此新方法设为虚拟(如您所做),但这与覆盖基类方法不同。

Der2当您重写Print时,实际上覆盖了在Der1声明的“新”版本 – 而不是版本是Base 。 Eric Lippert对一个稍微不同的问题有一个很好的答案 ,可以帮助你推断如何用C#语言处理虚拟方法。

在您的示例中,当您调用Print ,您在第一种情况下通过Base类型的引用调用它 – 因此调用Print的隐藏(但不是覆盖)版本。 另外两个调用被调度到Der1的实现,因为在这种情况下,您实际上已经覆盖了该方法。

您可以在新的和重写的MSDN文档中阅读有关此内容的更多信息。

您可能要对Der1做的事情(就像您对Der2所做的那样)是使用override关键字:

 class Base { public virtual void Print() { Console.WriteLine("Base"); } } class Der1 : Base { // omitting 'new' and using override here will override Base public override void Print() { Console.WriteLine("Der1"); } } 

这是因为Der1不会覆盖 Print它会将其替换为恰好具有相同名称的全新方法 (这是由使用new关键字引起的)。 因此,当对象被强制转换为Base它会调用Print in Base ; 没有覆盖来调用..

override将替换以前的方法,但是因为你的Der1类没有覆盖Print() (它使它成为阴影,使用VB-ism),所以调用了BasePrint()的最重写版本,这恰好发生在是它定义的版本

正如大家所说,类Der1正在替换Print()而不是覆盖它。 要查看此操作,您可以将d1d2基于Base ,然后调用print方法。 然后它将返回Base

 ((Base)d2).Print(); //Base