Смущен "переопределить" против "нового" в C # - PullRequest
25 голосов
/ 02 июня 2010

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

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

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

Ответы [ 4 ]

28 голосов
/ 02 июня 2010

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

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

В Der2 когда вы переопределяете Print, вы фактически переопределяете 'новую' версию, которую вы объявили в Der1, а не версию Base. У Эрика Липперта отличный ответ на немного другой вопрос, который может помочь вам понять, как обрабатываются виртуальные методы в языке 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"); 
    } 
} 
6 голосов
/ 02 июня 2010

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

1 голос
/ 02 июня 2010

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

0 голосов
/ 02 июня 2010

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

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