Добавить в цитаты Настройки чтения

Страница 163 из 502

<b>    Console.WriteLine(&quot;Метод Who() в классе Base&quot;);</b>

<b>  }</b>

<b>}</b>

<b>class Derived1 : Base {</b>

<b>  // Переопределить метод Who() в производном классе. </b>

<b>  public override void Who() {</b>

<b>    Console.WriteLine(&quot;Метод Who() в классе Derived1&quot;);</b>

<b>  }</b>

<b>}</b>

<b>class Derived2 : Derived1 {</b>

<b>  // В этом классе метод Who() не переопределяется.</b>

<b>}</b>

<b>class Derived3 : Derived2 {</b>

<b>  //И в этом классе метод Who() не переопределяется.</b>

<b>}</b>

<b>class No0verrideDemo2 {</b>

<b>  static void Main() {</b>

<b>    Derived3 dOb = new Derived3();</b>

<b>    Base baseRef; // ссылка на базовый класс</b>

<b>    baseRef = dOb;</b>

<b>    baseRef.Who(); // вызов метода Who() из класса Derivedl</b>

<b>  }</b>

<b>}</b>

Вот к какому результату приводит выполнение этого кода.

<b>Метод Who() в классе Derived1</b>

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

И еще одно замечание: свойства также подлежат модификации ключевым словом virtual и переопределению ключевым словом override. Это же относится и к индексаторам.

Благодаря переопределению методов в C# поддерживается динамический полиморфизм. В объектно-ориентированном программировании полиморфизм играет очень важную роль, потому что он позволяет определить в общем классе методы, которые становятся общими для всех производных от него классов, а в производных классах — определить конкретную реализацию некоторых или же всех этих методов. Переопределение методов — это еще один способ воплотить в C# главный принцип полиморфизма: один интерфейс — множество методов.

Удачное применение полиморфизма отчасти зависит от правильного понимания той особенности, что базовые и производные классы образуют иерархию, которая продвигается от меньшей к большей специализации. При надлежащем применении базовый класс предоставляет все необходимые элементы, которые могут использоваться в производном классе непосредственно. А с помощью виртуальных методов в базовом классе определяются те методы, которые могут быть самостоятельно реализованы в производном классе. Таким образом, сочетая наследование с виртуальными методами, можно определить в базовом классе общую форму методов, которые будут использоваться во всех его производных классах.

Для того чтобы стали понятнее преимущества виртуальных методов, применим их в классе TwoDShape. В предыдущих примерах в каждом классе, производном от класса TwoDShape, определялся метод Area(). Но, по-видимому, метод Area() лучше было бы сделать виртуальным в классе TwoDShape и тем самым предоставить возможность переопределить его в каждом производном классе с учетом особенностей расчета площади той двумерной формы, которую инкапсулирует этот класс. Именно это и сделано в приведенном ниже примере программы. Ради удобства демонстрации классов в этой программе введено также свойство name в классе TwoDShape.

<b>// Применить виртуальные методы и полиморфизм<sup>-</sup>.</b>

<b>using System;</b>

<b>class TwoDShape { </b>

<b>  double pri_width;</b>

<b>  double pri_height;</b>

<b>  // Конструктор по умолчанию,</b>

<b>  public TwoDShape() {</b>

<b>    Width = Height = 0.0;</b>

<b>    name = &quot;null&quot;;</b>

<b>  }</b>

<b>  // Параметризированный конструктор.</b>

<b>  public TwoDShape(double w, double h, string n) {</b>

<b>    Width = w;</b>

<b>    Height = h; </b>

<b>    name = n;</b>

<b>  }</b>

<b>  // Сконструировать объект равной ширины и высоты,</b>

<b>  public TwoDShape(double x, string n) {</b>

<b>    Width = Height = x;</b>

<b>    name = n;</b>

<b>  }</b>