Давайте рассмотрим простой пример.
B B1 B2
| \ /
D D
Слева мы находим класс, производный от одного баса.Очевидно, что в ОО-дизайне разумно иметь отношения is-a, уважающие принцип замены Лискова.
Справа оба B1
и B2
являются независимыми основаниями D
, и D
может бытьдоступ полиморфно с использованием B1*
или B2*
(или ссылок).Надеемся, что мы можем принять, что это также допустимый ОО-проект (несмотря на то, что Sun считает его слишком напряженным для программистов на Java ;-P).Затем рассмотрите возможность использования некоторой базовой функциональности как из B1
, так и B2
и сделайте ее многоразовой: скажем, они оба работают с произвольным списком чисел, которым они могут разумно предоставить прямой / public
доступ:
Container<int> Container<int>
\ /
B1 B2
\ /
D
Если это еще не щелчок, возможно:
Container<int> Container<int>
\ /
Ages Heights
\ /
Population
Разумно сказать, что Ages
is-a Container<int>
, хотя это может добавить некоторые удобные функции, такие как average
,min
, max
, num_teenagers
.То же самое для Heights
, возможно, с другим набором вспомогательных функций.Очевидно, что Population
может быть разумно заменено на Ages
или Heights
коллекцию (например, size_t num_adults(Ages&); if (num_adults(my_population)) ...
).
Дело в том, что каждый поддерживающий контейнер не должен иметь 1: 1связь с другими производными классами, такими как Population
;скорее, он должен быть точно 1: 1 с его непосредственно полученным классом .
Опять же, использование состава или наследования является решением дизайна интерфейса, но это не обязательно неверно для предоставленияконтейнеры публично таким образом.(Если есть проблема с поддержкой Population
инвариантов, таких как Ages::empty() == Heights::empty()
, функции преобразования данных Container<int>
могут быть сделаны protected
, в то время как const
функции-члены были public
.)
Как выобратите внимание, что Population
не имеет однозначного отношения is с Container<int>
, и для кода может потребоваться явное устранение неоднозначности.Это уместно.Конечно, для Population
также возможно и разумно получить из Container<int>
, если он хранит какой-то другой набор чисел, но это будет независимо от косвенно унаследованных контейнеров.
Мой вопрос, кроме того, что «это действительно не отношения, я использовал непонятное публичное наследование как синтаксическое удобство, когда оно не было концептуально обоснованным»
Я не вижу проблем с is-отношения или концептуальная обоснованность вышесказанного, если вы действительно объясните, пожалуйста ...
"Мне никогда не нужно полиморфно ссылаться на базовый класс из самого производного класса, так что невероятно небольшие издержкиэто того не стоит "
Я думаю, ясно, что я просто делаю моделирование данных, основанное на связях с естественными объектами, а не на какой-то сомнительной оптимизации.Вспомогательный контейнерный класс, выделенный из баз, фактически используется и должен быть независимым в каждом.