Стандарты программирования на С++


Обсуждение


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

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

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

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




Содержание  Назад  Вперед