2010-06-01 59 views
25

我有以下类:困惑在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出来了。

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

+0

真是一个惊人的例子... 唯一的技巧就是在这里 - intially,BASE的方法是通过的“DER-1”的虚方法隐藏的,所以在骑的“方法DER-2 “无法实施。因此,我们获得了BASE的价值。 – Kings 2015-05-07 15:21:05

回答

27

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

当您在方法签名上使用new关键字时 - 您告诉编译器,这是一种恰好与您的某个基类的方法名称相同的方法 - 但没有其他关系。你可以使这个新方法变成虚拟的(就像你所做的那样),但这不像重写基类方法一样。

Der2当你重写Print你实际上是覆盖您在Der1声明的“新”版本 - 不是版本为Base。 Eric Lippert有一个excellent answer这个稍微不同的问题,可以帮助你推断如何在C#语言中处理虚拟方法。

在您的例子,当你调用Print,你在呼唤它在第一种情况下,通过Base类型的引用 - 这样的隐藏(但没有覆盖)的Print版本被调用。另外两个调用被调度到Der1的实现,因为在这种情况下,你实际上已经覆盖了该方法。

您可以在MSDN documentation of new and override中阅读更多关于此的内容。

你可能已经打算与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"); 
    } 
} 
+0

这就是他对Der2所做的。 – GalacticCowboy 2010-06-01 20:09:26

+0

@GalacticCowboy - 的确,那是我的观点。这可能也是Der1中的目标,但不知何故,'new'关键字被滑入,而不是'override'。我会更新我的帖子,使其更清晰。 – LBushkin 2010-06-01 20:11:52

+0

谢谢。一个很好的答案,我完全理解它现在如何工作。 – iTayb 2010-06-01 20:18:13

5

这是因为Der1覆盖Print其与替换它全新的方法碰巧具有相同的名称(这是由使用new关键字引起的)。所以,当物体投射到Base时,它会调用Print,Base;没有覆盖调用..

1

override将取代以往的方法,但你Der1类没有重载Print()(它的阴影它,使用VB-ISM),然后BasePrint()的最优化版本被覆盖的调用,这恰好是它定义的版本

0

正如大家所说的,Der1类正在取代Print()而不是覆盖它。要看到这个动作,你可以基于d1d2Base,然后调用打印方法。然后它将返回Base

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