Наследование это вторая по силе (после отношений дружбы) взаимосвязь, которую можно выразить в C++. Сильные связи нежелательны, их следует избегать везде, где только можно.
Композиция означает простое использование некоторого типа в виде переменной-члена в другом типе. В этом случае вы можете хранить и использовать объект таким образом, который обеспечивает вам контроль над степенью взаимосвязи.
Преимущества композиции перед наследованием:
1. Большая гибкость без влияния на вызывающий код - Закрытые члены данные находятся под полным вашим контролем.
Вы можете хранить их по значению посредством интеллектуального указателя или с использованием идиомы Pimpl. При этом переход от одного способа хранения к другому никак не влияет на код вызываемой функции: меняется только реализация функций-членов класса, использующих эти упомянутые члены-данные.
- Если вы решите, что вам требуется иная функциональность вы можете легко изменить тип или способ хранения члена при полной сохранности открытого интерфейса.
Если же вы начнёте с открытого наследования, то, скорее всего, вы не сможете легко и просто изменить ваш базовый класс в случае необходимости. 2. Большая обособленность в процессе компиляции и уменьшение её времени- Хранение объекта посредством интеллектуального указателя, а не в виде непосредственного члена или базового класса позволяет даже снизить зависимости заголовочных файлов, так как объявление указателя на объект не требует полного определения класса этого объекта.
- Наследование напротив всегда требует видимости полного определения базового класса.
- Часто собирают все закрытые члены воедино посредством одного непрозрачного указателя (идиома Pimpl).
3. Меньше странностей- Наследование от некоторого типа может вызвать проведение поиска имён среди функций и шаблонов функций, определённых в том же пространстве имён, что и упомянутый тип.
Этот момент с трудом поддаётся отладке.
4. Большая применимость - Не все классы проектируются с учётом того, что они будут выступать в роли базовых. Однако большинство классов вполне могут справиться с ролью члена.
5. Большая надёжность - Более сильное связывание путём наследования затрудняет написание безопасного в смысле ошибок кода.
6. Меньшая сложность и хрупкость - Наследование приводит к дополнительным усложнениям таким как сокрытие имён и другим, возникающим при внесении изменений в базовый класс.
Исключения: Используйте открытое наследование для моделирования зависимостей.
Закрытое и защищённое наследование нужно если: - если требуется перекрытие виртуальной функции
- если нужен доступ к защищённому члену
- если надо создать объект до используемого, а уничтожить - после, тогда сделайте его базовым классом
- если вам приходится заботиться о виртуальных базовых классах
- если вы знаете, что получите выгоду от оптимизации пустого базового класса, которая будет выполнена используемым компилятором
- если вам требуется управляемый полиморфизм, то есть отношение заменимости, которое должно быть видно только определённому коду ( посредством дружбы)
|