Подтвердить что ты не робот

Смутно о "переопределении" против "нового" в С#

У меня следующие классы:

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 вышел.

Как это возможно? Как переопределение там не работало?

4b9b3361

Ответ 1

Вы никогда не превышали версию Base Print(). Вы только скрыли его с помощью отдельного виртуального метода (именованного таким же) в Der1.

Когда вы используете ключевое слово new в сигнатуре метода - вы сообщаете компилятору, что это метод, который имеет одно имя как метод одного из ваших базовых классов, но не имеет другого отношения. Вы можете сделать этот новый метод виртуальным (как вы это сделали), но это не то же самое, что переопределить метод базового класса.

В Der2, когда вы переопределяете Print, вы фактически переопределяете "новую" версию, указанную в Der1, а не версию Base. Eric Lippert имеет отличный ответ на несколько другой вопрос, который может помочь вам понять, как обрабатываются виртуальные методы на языке С#.

В вашем примере, когда вы вызываете 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"); 
    } 
} 

Ответ 2

Это потому, что Der1 не переопределяет Print, он заменяет его совершенно новым методом, который имеет одно и то же имя (это вызвано использованием new). Итак, когда объект передается в Base, он вызывает Print в Base; для вызова не существует переопределения.

Ответ 3

override заменит предыдущий метод, но поскольку ваш класс Der1 не переопределяет Print() (он Shadows it, чтобы использовать VB-ism), то самый превышенный verion Base Print(), который является версией, которую он определяет

Ответ 4

Как сказал каждый, класс Der1 заменяет Print() вместо его переопределения. Чтобы увидеть это в действии, вы можете установить d1 и d2 в Base, а затем вызвать метод печати. Затем он вернет Base.

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