Программирование >>  Программирование с использованием ajax 

1 ... 62 63 64 [ 65 ] 66 67 68 ... 396


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

Механизм наследования позволяет расширять или создавать специфические классы от одного более общего базового класса. Например, возьмем класс, представляющий животное с фермы. Этот класс мог бы называться Animal (Животное) и обладать методами вроде Eat Food () (Кормить) или Breed () (Разводить). От него можно было бы создать производный класс по имени Cow (Корова), который бы поддерживал все те же самые методы, но при этом также имел и свои собственные, например, Моо () (Мычать) и SupplyMilk О (Давать молоко), а также еще один производный класс по имени Chicken (Курица) с методами Cluck () (Кудахтать) и LayEgg () (Снести яйцо).

В UML наследование изображается с помощью стрелок, как показано на рис. 8.7.

Animal

-HEatFoodO -HBreedO

Chicken

-HCIuckO +LayEgg()

-hMooO -HSupplyMilkO

Puc. 8.7. Представлени£ отногиений наследования в UML На рис. 8.7 возвращаемые типы членов для простоты не показаны.

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

Для исключения вероятности возникновения подобной проблемы существует еще и третий уровень доступности - protected, при котором доступ к члену имеют только производные классы. Что касается внешнего кода, то для него член с уровнем доступности protected идентичен члену с уровнем private.

Помимо уровня защиты для члена еще также может определяться и поведение, связанное с наследованием. Члены базового класса могут быть виртуальными (virtual), а это означает то, что они могут переопределяться в классе, который их наследует. Другими словами, в производном классе для членов может предоставляться альтернативная реализация. Эта альтернативная реализация не подразумевает удаление ис-



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

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

В примере с классом Animal можно было бы сделать виртуальным метод EatFood () и предоставить для него новую реализацию в каком-то производном классе, например, в Cow, как показано на рис. 8.8. На этом рисунке метод EatFood () отображается и в классе Animal, и в классе Cow; это указывает на то, что у каждого из классов имеется своя собственная реализация данного метода.

Animal

-HEatFoodO -HBreedO

-zx-

Chicken

-hCluckO +LayEgg()

-hMooO

-hSupplyMiIkO

-hEatFoodO

Puc. 8.8. Представление виртуального метода в UML

Базовые классы могут также определяться как абстрактные (abstract). Создавать экземпляр абстрактного класса напрямую нельзя; использовать такой класс можно только путем выполнения от него наследования. У абстрактных классов могут быть абстрактные члены, которые не могут иметь никакой реализации в базовом классе и для которых реализация должна предоставляться в производных классах. Например, если бы класс Animal был абстрактным, тогда в UML-представлении он выглядел бы так, как показано на рис. 8.9.

Имена абстрактных классов в UML изображаются с курсивным начертанием (или с использованием пунктирной линии для содержащего их прямоугольника).

На рис. 8.9 методы EatFood () и Breed () отображаются в прямоугольниках абстрактных классов Chicken и Cow; это указывает на то, что они являются либо абстрактными (и тогда подлежат переопределению в других производных классах), либо виртуальными (т.е. уже были переопределены в самих классах Chicken и Cow). Разумеется, абстрактные базовые классы могут предоставлять реализацию для членов, что встречается очень часто. Невозможность создания экземпляра абстрактного класса вовсе не означает, что в нем нельзя инкапсулировать функциональные возможности.



Animal

+EatFood() +Breed()

Chicken

+Cluck() +LayEgg() +EatFood() -i-BreedO

+Moo() +SupplyMilk() +EatFood() +Breed()

Puc. 8.9. Представление абстрактных классов в UML

И, наконец, еще классы могут быть герметизированными (sealed). Такие классы не могут выступать в роли базового класса и, следовательно, не могут иметь и никаких производных классов.

В языке С# предусмотрен один общий базовый класс для всех объектов, имеющий имя object (которое является псевдонимом класса System. Ob j ect из .NET Framework). Этот класс более подробно рассматривается в главе 9.

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

Полиморфизм

Одним из результатов наследования является наличие в классах, унаследованных от базового, некоторых совпадений с ним среди предоставляемых ими методов и свойств. Благодаря этому зачастую оказывается возможным применять для объектов, которые создаются от классов с общим базовым типом, идентичный синтаксис. Например, при наличии у класса Animal метода по имени EatFood () синтаксис для вызова этого метода из производных классов Cow и Chicken будет выглядеть почти одинаково:

Cow myCow = new Cow() ;

Chicken myChicken = new ChickenO;

myCow.EatFood() ;

myChicken.EatFood() ;

Полиморфизм (polymorphism) позволяет двиьуться еще дальше, а именно - присваивать переменную базового типа переменной одного из производных типов, как показано ниже:

Animal myAnimal = myCow;

Никакого приведения выполнять не требуется. Далее можно просто вызывать методы базового класса через эту переменную:

myAnimal.EatFood() ;



1 ... 62 63 64 [ 65 ] 66 67 68 ... 396

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика