Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 86

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 80 81 82 83 84 85 < 86 > 87 88 89 90 91 92 .. 105 >> Следующая

Выразить это на С++ можно следующим образом:
class CartoonCharacter { public :
virtual void dance () {}
virtual void sing() {}
};
Виртуальные функции естественным образом отражают тот факт, что пение и танец имеют смысл для всех объектов CartoonCharacter. Поведение по умолчанию можно выразить пустыми определениями соответствующих функций класса (см. правило 36).
Допустим, что один из типов персонажей - кузнечик, который танцует и поет особым образом:
class Grasshopper: public CartoonCharacter { public :
virtual void dance () ; Il Определение в другом месте, virtual void sing() ; Il Определение в другом месте.
};
Теперь предположим, что после реализации класса Grasshopper вам понадобился класс для сверчков:
class Cricket: public CartoonCharacter { public :
virtual void dance ();
virtual void sing();
};
Когда вы принимаетесь за реализацию класса Cricket, вы осознаете, что можете повторно использовать значительную часть класса Grasshopper. Однако этот код в разных местах необходимо слегка модифицировать, чтобы отразить различия в пении и танце кузнечиков и сверчков. Вас неожиданно осеняет, каким образом повторно использовать существующий код: вы реализуете класс Cricket посредством класса Grasshopper и применяете виртуальные функции для того, чтобы позволить классу Cricket изменить поведение класса Grasshopper!
Сразу же становится ясно, что одновременное выполнение двух требований -наличия отношения «реализация посредством» и возможности переопределять виртуальные функции - означает необходимость закрытого наследования Cricket от Grasshopper. При этом сверчок, разумеется, - персонаж мультфильма, поэтому вы переопределяете класс Cricket так, чтобы он наследовал как от Grasshopper, так и от CartoonCharacter:
Правило 43
class Cricket .-public CartoonCharacter, private Grasshopper { public:
virtual void dance () ;
virtual void singO ;
і ''-
Затем вы начинаете вносить необходимые изменения в класс Grasshopper. В частности, требуется объявшъ ряд новых виртуальных функций, которые можно будет потом переопределять в Cricket:
class Grasshopper: public CartoonCharacter { public:
virtual void dance () ; virtual void singO ; protected:
virtual void danceCustomizationl(); virtual void danceCustomization2(); virtual- void singCustomization() ;
};
Танец кузнечика теперь определяется следующим образом:
void Grasshopper:: dance () {
выполнить общие танцевальные действия danceCustomizationl();
выполнить другие общие танцевальные действия danceCustomization2(); завершить общие танцевальные действия
|}
Пение кузнечика определяется аналогичным образом.
Ясно, что класс Cricket должен быть обновлен с учетом новых виртуальных /нкций, требующих переопределения:
class Cricket:public CartoonCharacter, private Grasshopper { public :
virtual void dance () { Grasshopper:: dance (); } virtual void singO { Grasshopper: :sing() ; } protected:
virtual void danceCustomizationl(); virtual void danceCustomization2(); virtual void singCustomization () ;
};
Кажется, что все работает здорово. Когда вы предлагаете объекту Cricket Танцевать, он выполняет обычный код dance из класса Grasshopper, затем -специальный код класса Cricket, после чего продолжает выполнение кода из Grasshopper: : dance и т.д.
Однако данный фрагмент таит в себе существенный недостаток: вы опрометчиво попали под бритву Оккама, что, вообще говоря, плохо, какова бы ни была бритва, а уж тем более плохо, если это бритва Уильяма Оккама. Он учит,
І
Наследование и ООП
что сущности не следует умножать без необходимости, а в нашем случае сущности - это отношения наследования. Если вы считаете, чго множественное наследование сложнее простого (а я подозреваю, что это именно так), то подобная реализация класса Cricket является чрезмерно сложной.
W Суть проблемы состоит в том, что утверждение «класс Cricket реализуется посредством класса Grasshopper» неверно. На самом деле класс Cricket и класс Grasshopper используют общий код. В частности, они оба применяют код, определяющий общие черты в поведении кузнечиков и сверчков при танце и пении.
Выразить некоторую общность двух классов следует не с помощью наследования одного от другого, а с помощью наследования от общего базового класса. Общий для кузнечика и сверчка код не принадлежит ни классу Cricket, ни классу Grasshopper. Он относится к новому классу, от которого они оба наследуют, -скажем, Insect:
class CartoonCharacter { ... } ; class Insect: public CartoonCharacter { public :
virtual void dance () ,- Il Общий код для кузнечиков
virtual void sing(); Il и сверчков,
protected:
virtual void danceCustomizationl () = 0; virtual void danceCustomization2 () = 0; virtual void singCustomization() = 0;
};
class Grasshopper: public Insect { protected:
virtual void danceCustomizationl();
virtual void danceCustomization2();
virtual void singCustomization () ;
};
class Cricket: public Insect { protected:
virtual void danceCustomizationl () ;
virtual void danceCustomization2();
virtual void singCustomization();
Предыдущая << 1 .. 80 81 82 83 84 85 < 86 > 87 88 89 90 91 92 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100