C # Скрытие, переопределение и вызов функции из базового класса - PullRequest
15 голосов
/ 23 марта 2010

Я изучаю C # и столкнулся со следующей проблемой.У меня есть два класса: базовый и производный:

class MyBase
{
    public void MyMethod()
    {
        Console.WriteLine("MyBase::MyMethod()");
    }
}


class MyDerived: MyBase
{
    public void MyMethod()
    {
        Console.WriteLine("MyDerived::MyMethod()");
    }
}

Пока без ключевых слов virtual и override.Когда я компилирую это, я получаю предупреждение (которое, конечно, ожидается), что я пытаюсь скрыть MyMethod от MyBase класса.

Что я хочу сделать, это вызвать метод из базового классаэкземпляр производного класса.Я делаю это так:

MyDerived myDerived = new MyDerived();
((MyBase)myDerived).MyMethod();

Работает нормально, когда в методах не указаны ключевые слова virtual и т. Д.Я попытался ввести комбинацию ключевых слов и получил следующие результаты:

| MyBase::MyMethod | MyDerived::MyMethod | Result printed on the console |
| -----------------|---------------------|-------------------------------|
| -                | -                   | MyBase::MyMethod()            |
| -                | new                 | MyBase::MyMethod()            |
| virtual          | new                 | MyBase::MyMethod()            |
| virtual          | override            | MyDerived::MyMethod()         |

Надеюсь, таблица вам понятна. У меня два вопроса :

  1. Это правильный способ вызова функции из базового класса (((MyBase)myDerived).MyMethod();)?Я знаю о ключевом слове base, но его можно вызывать только из производного класса.Правильно ли это?
  2. Почему в последнем случае (с модификаторами virtual и override) вызванный метод был получен из производного класса?Не могли бы вы объяснить это?

Ответы [ 4 ]

18 голосов
/ 23 марта 2010

Когда вы вызываете метод virtual для экземпляра типа, который переопределяет метод, переопределенная версия будет вызываться всегда, даже если вы приведете к базовому классу.

Единственный способ вызвать базовую реализацию виртуального метода для класса, который переопределяет метод, - это создать второй метод в производном классе (не базовом классе), который вызывает метод с использованием ключевого слова base.

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

3 голосов
/ 23 марта 2010

Что касается вашего второго вопроса, вы не меняете тип объекта, на который ссылаетесь, а только интерфейс, через который вы ссылаетесь.Поэтому, если у вас есть объект B, который наследует от A и переопределяет функцию C, даже если вы ссылаетесь на B как на A, он все равно вызывает реализации самого производного типа, в данном случае B.

2 голосов
/ 23 марта 2010
  1. Вы правы, base относится к базовому классу для данного экземпляра.
  2. Включенный механизм называется полиморфизмом: лучше работать без предупреждения. Хороший способ ориентирования на природный объект - последний из упомянутых вами случаев.

Кстати, старайтесь избегать написания кода, который обеспечивает принцип подстановки, другими словами, не пишите код, который зависит от реализации вашей иерархии классов, потому что вам придется изменить этот код, если вы добавите новый производный класс для вашего базового класса.

2 голосов
/ 23 марта 2010

Вы правы - base можно вызывать только из производного класса - Источник .

На этой странице также приведен пример того, как переопределить определение базового класса.

...