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

iTa*_*ayb 25 c# virtual overriding new-operator

我有以下课程:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要方法:

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

b.Print();
d1.Print();
d2.Print();
Run Code Online (Sandbox Code Playgroud)

输出是Base,Der2,Der2.

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

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

LBu*_*kin 28

你从来没有真正覆盖过的Base版本Print().您只使用单独的虚拟方法(名称相同)隐藏它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"); 
    } 
} 
Run Code Online (Sandbox Code Playgroud)


Fre*_*örk 6

这是因为Der1没有覆盖 Print,它用一个恰好具有相同名称的全新方法替换它(这是由使用new关键字引起的).所以,当对象被强制转换为BasePrintBase; 没有覆盖来调用..