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

时间:2010-06-01 20:00:11

标签: c# virtual override 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");
    }
}

这是我的主要方法:

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

b.Print();
d1.Print();
d2.Print();

输出为BaseDer2Der2

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

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

4 个答案:

答案 0 :(得分:28)

您实际上从未覆盖Base Print()版本的Der1。您只在new中使用单独的虚拟方法(名称相同)隐藏了它。

当您在方法签名上使用Der2关键字时 - 您告诉编译器这是一个碰巧与您的某个基类的方法同名的方法 - 但没有其他关系。你可以将这个新方法设为虚拟(就像你已经完成的那样),但这与覆盖基类方法不同。

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

在您的示例中,当您致电Base时,您通过Print类型的引用在第一种情况下调用它 - 所以Der1的隐藏(但不是覆盖)版本叫做。另外两个调用被分派到override的实现,因为在这种情况下,你实际上已经覆盖了该方法。

您可以在MSDN documentation of new and override

中详细了解相关信息

您可能要对Der1做的事情(就像您对Der2所做的那样)是使用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"); } } 关键字:

{{1}}

答案 1 :(得分:6)

这是因为Der1没有覆盖 Print它用一个恰好具有相同名称的全新方法取代它(这是由使用new关键字引起的。因此,当对象转换为Base时,它会在Print中调用Base;没有覆盖来调用..

答案 2 :(得分:1)

override将取代之前的方法,但由于您的Der1类不会覆盖Print()(它使用阴影,使用VB-ism),因此最重要的版本调用了Base的{​​{1}},这恰好是它定义的版本

答案 3 :(得分:0)

正如大家所说,课程Der1正在取代Print()而不是覆盖它。要查看此操作,您可以将d1d2设为Base,然后调用print方法。然后它将返回Base

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