Литмир - Электронная Библиотека
A
A

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

Учитывая отношение между этими двумя типами классов, вот как можно работать с классом

MiniVan
:

Console.WriteLine("***** Basic Inheritance *****\n");

...

// Создать объект MiniVan.

MiniVan myVan = new MiniVan {Speed = 10};

Console.WriteLine("My van is going {0} MPH", myVan.Speed);

Console.ReadLine();

Обратите внимание, что хотя в класс

MiniVan
никакие члены не добавлялись, в нем есть прямой доступ к открытому свойству
Speed
родительского класса; тем самым обеспечивается повторное использование кода. Такой подход намного лучше, чем создание класса
MiniVan
, который имеет те же самые члены, что и класс
Car
, скажем, свойство
Speed
. Дублирование кода в двух классах приводит к необходимости сопровождения двух порций кода, что определенно будет непродуктивным расходом времени.

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

Console.WriteLine("***** Basic Inheritance *****\n");

...

// Создать объект MiniVan.

MiniVan myVan = new MiniVan();

myVan.Speed = 10;

Console.WriteLine("My van is going {0} MPH",

                   myVan.Speed);

<b>// Ошибка! Доступ к закрытым членам невозможен!</b>

myVan._currSpeed = 55;

Console.ReadLine();

В качестве связанного примечания: даже когда класс

MiniVan
определяет собственный набор членов, он по-прежнему не будет располагать возможностью доступа к любым закрытым членам базового класса
Car
. Не забывайте, что закрытые члены доступны только внутри класса, в котором они определены. Например, показанный ниже метод в
MiniVan
приведет к ошибке на этапе компиляции:

// Класс MiniVan является производным от Car.

class MiniVan : Car

{

  public void TestMethod()

  {

    // Нормально! Доступ к открытым членам родительского

    // типа в производном типе возможен.

    Speed = 10;

    // Ошибка! Нельзя обращаться к закрытым членам

    // родительского типа из производного типа!

    _currSpeed = 10;

  }

}

Замечание относительно множества базовых классов

Говоря о базовых классах, важно иметь в виду, что язык C# требует, чтобы отдельно взятый класс имел в точности один непосредственный базовый класс. Создать тип класса, который был бы производным напрямую от двух и более базовых классов, невозможно (такой прием, поддерживаемый в неуправляемом языке C++, известен как множественное наследование). Попытка создать класс, для которого указаны два непосредственных родительских класса, как продемонстрировано в следующем коде, приведет к ошибке на этапе компиляции:

// Недопустимо! Множественное наследование

// классов в языке C# не разрешено!

class WontWork

  : BaseClassOne, BaseClassTwo

{}

В главе 8 вы увидите, что платформа .NET Core позволяет классу или структуре реализовывать любое количество дискретных интерфейсов. Таким способом тип C# может поддерживать несколько линий поведения, одновременно избегая сложностей, которые связаны с множественным наследованием. Применяя этот подход, можно строить развитые иерархии интерфейсов, которые моделируют сложные линии поведения (см. главу 8).

Использование ключевого слова sealed

Язык C# предлагает еще одно ключевое слово,

sealed
, которое предотвращает наследование. Когда класс помечен как
sealed
(запечатанный), компилятор не позволяет создавать классы, производные от него. Например, пусть вы приняли решение о том, что дальнейшее расширение класса
MiniVan
не имеет смысла:

// Класс Minivan не может быть расширен!

sealed class MiniVan : Car

{

}

Если вы или ваш коллега попытаетесь унаследовать от запечатанного класса

MiniVan
, то получите ошибку на этапе компиляции:

// Ошибка! Нельзя расширять класс, помеченный ключевым словом sealed!

class DeluxeMiniVan

  : MiniVan

{

}

Запечатывание класса чаще всего имеет наибольший смысл при проектировании обслуживающего класса. Скажем, в пространстве имен

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

// Еще одна ошибка! Нельзя расширять класс, помеченный как sealed!

132
{"b":"847442","o":1}