Мегаобучалка Главная | О нас | Обратная связь


Открытое наследование означает заменимость. Наследовать надо не для повторного использования, а чтобы быть повторно использованным



2016-01-26 429 Обсуждений (0)
Открытое наследование означает заменимость. Наследовать надо не для повторного использования, а чтобы быть повторно использованным 0.00 из 5.00 0 оценок




 

 

Резюме

 

Открытое наследование позволяет указателю или ссылке на базовый класс в действительности обращаться к объекту некоторого производного класса без изменения существующего кода и нарушения его корректности.

Не применяйте открытое наследование для того, чтобы повторно использовать код (находящийся в базовом классе); открытое наследование необходимо для того, чтобы быть повторно использованным (существующим кодом, который полиморфно использует объекты базового класса).

 

Обсуждение

 

Несмотря на двадцатилетнюю историю объектно-ориентированного проектирования, цель и практика открытого наследования часто понимается неверно, и многие применения наследования оказываются некорректными.

Открытое наследование в соответствии с принципом подстановки Лисков (Liskov Substitution Principle [Liskov88]) всегда должно моделировать отношение "является" ("работает как"): все контракты базового класса должны быть выполнены, для чего все перекрытия виртуальных функций-членов не должны требовать большего или обещать меньше, чем их базовые версии. Код, использующий указатель или ссылку на Base, должен корректно вести себя в случае, когда указатель или ссылка указывают на объект Derived.

Неверное использование наследования нарушает корректность. Обычно некорректно реализованное наследование не подчиняется явным или неявным контрактам, установленным базовым классом. Такие контракты могут оказаться очень специфичными и хитроумными, и программист должен быть особенно осторожен, когда их нельзя выразить непосредственно в коде (некоторые шаблоны проектирования помогают указать в коде его предназначение — см. рекомендацию 39).

Наиболее часто в этой связи упоминается следующий пример. Рассмотрим два класса — Square (квадрат) и Rectangle (прямоугольник), каждый из которых имеет виртуальные функции для установки их высоты и ширины. Тогда Square не может быть корректно унаследован от Rectangle, поскольку код, использующий видоизменяемый Rectangle, будет полагать, что функция SetWidth не изменяет его высоту (независимо от того, документирован ли данный контракт классом Rectangle явно или нет), в то время как функция Square::SetWidth не может одновременно выполнить этот контракт и свой инвариант "квадратности". Но и класс Rectangle не может корректно наследовать классу Square, если его клиенты Square полагают, например, что для вычисления его площади надо возвести в квадрат ширину, либо используют какое-то иное свойство, которое выполняется для квадрата и не выполняется для прямоугольника

Описание "является" для открытого наследования оказывается неверно понятым при использовании аналогий из реального мира: квадрат "является" прямоугольником в математическом смысле, но с точки зрения поведения Square не является Rectanglе. Вот почему вместо "является" мы предпочитаем говорить "работает как" (или, если вам это больше нравится, "используется как") для того, чтобы такое описание воспринималось максимально правильно.

Открытое наследование действительно связано с повторным использованием, но опять же не так, как привыкло думать множество программистов. Как уже указывалось, цель открытого наследования — в реализации заменимости (см. [Liskov88]). Цель отрытого наследования не в том, чтобы производный класс мог повторно использовать код базового класса для того, чтобы с его помощью реализовать свою функциональность. Такое отношение "реализован посредством" вполне корректно, но должно быть смоделировано при помощи композиции или, только в отдельных случаях, при помощи закрытого или защищенного наследования (см. рекомендацию 34).

Вот еще одно соображение по поводу рассматриваемой темы. При корректности и целесообразности динамического полиморфизма композиция "эгоистична" в отличие от "щедрого" наследования. Поясним эту мысль.

Новый производный класс представляет собой частный случай существующей более общей абстракции. Существующий (динамический) полиморфный код, который использует Base& или Base* путем вызова виртуальных функций Base, должен быть способен прозрачно использовать объекты класса MyNewDerivedType, производного от Base. Новый производный тип добавляет новую функциональность к существующему коду, который при этом не должен изменяться. Однако несмотря на неизменность имеющегося кода, при использовании им новых производных объектов его функциональность возрастает.

Новые требования, естественно, должны удовлетворяться новым кодом, но они не должны требовать внесения изменений в существующий код (см. рекомендацию 36).

До объектно-ориентированного программирования было легко решить вопрос вызова старого кода новым. Открытое наследование упростило прозрачный и безопасный вызов нового кода старым (так что применяйте шаблоны, предоставляющие возможности статического полиморфизма, который хорошо совместим с полиморфизмом динамическим — см. рекомендацию 64).

 

Исключения

 

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

 

Ссылки

 

[Cargill92] pp. 19-20 • [Cline99] §5.13, §7.01-8.15 • [Dewhurst03] §92 • [Liskov88] • [Meyers97] §35 • [Stroustrup00] §12.4.1, §23.4.3.1, §24.3.4 • [Sutter00] §22-24

 



2016-01-26 429 Обсуждений (0)
Открытое наследование означает заменимость. Наследовать надо не для повторного использования, а чтобы быть повторно использованным 0.00 из 5.00 0 оценок









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

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Как вы ведете себя при стрессе?: Вы можете самостоятельно управлять стрессом! Каждый из нас имеет право и возможность уменьшить его воздействие на нас...
Как построить свою речь (словесное оформление): При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою...
Почему двоичная система счисления так распространена?: Каждая цифра должна быть как-то представлена на физическом носителе...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (429)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.006 сек.)