对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();
输出为Base
, Der2
, Der2
。
据我所知,即使指针指向它们,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),所以调用了Base
的Print()
的最重写版本,这恰好发生在是它定义的版本
正如大家所说,类Der1
正在替换Print()
而不是覆盖它。 要查看此操作,您可以将d1
和d2
基于Base
,然后调用print方法。 然后它将返回Base
。
((Base)d2).Print(); //Base