Ответ, данный itowlson , довольно хорошо охватывает большую часть вопроса. Сейчас я рассмотрю самый последний абзац настолько просто, насколько смогу.
Наследование должно быть реализовано для повторного использования, чтобы ваш производный класс был повторно использован в старом коде, а не для вашего класса, повторно использующего части базового класса (для этого можно использовать агрегирование).
С этой точки зрения, если у вас есть класс, который должен использоваться в новом коде с некоторой новой функциональностью, но должен прозрачно использоваться как прежний класс, тогда наследование - это ваше решение. Новый код может использовать новые функциональные возможности, а старый код будет беспрепятственно использовать ваши новые объекты.
Хотя это и есть общее намерение, есть некоторые общие питфалы, линия здесь тонкая, и ваш вопрос касается именно этой линии. Если у вас есть коллекция объектов типа base, это должно быть потому, что эти объекты предназначены для использования только с методами base. Они являются «базами», ведут себя как базы.
Использование методов в качестве 'instanceof' или downcasts (dynamic_cast <> () в C ++) для определения реального типа среды выполнения - это то, что я бы отметил в обзоре кода и принял только после того, как программист подробно объяснит, почему любые другие вариант хуже, чем это решение. Я бы принял это, например, в ответе itowlson при условии, что информация не доступна с данными операциями в базе. То есть базовый тип не имеет какого-либо метода, который предлагал бы вызывающей стороне достаточно информации для определения цвета. И если нет смысла включать такую операцию: помимо цвета препрезентации, собираетесь ли вы выполнять какие-либо операции над объектами на основе этой же информации? Если логика зависит от реального типа, то операция должна быть в базовом классе, чтобы быть переопределенной в производных классах. Если это невозможно (операция является новой и только для некоторых заданных подтипов), в базе должна быть, по крайней мере, операция, позволяющая вызывающему абоненту определить, что обратное преобразование не завершится неудачей. И опять же, мне бы действительно потребовалась веская причина, чтобы код вызывающей стороны требовал знания реального типа. Почему пользователь хочет видеть его в разных цветах? Будет ли пользователь выполнять различные операции для каждого из типов?
Если вам в конечном итоге требуется использовать код для обхода системы типов, ваш дизайн имеет странный запах . Конечно, никогда не говори никогда, но ты можешь с уверенностью сказать: избегай зависимости от instanceof или понижений для логики.