Следует отметить, что компонентный подход, применяемый в Visual C++ (ActiveX), зарекомендовал себя в качестве более инертного. Наследование дельфийских компонентов и переопределение их виртуальных функций выполнить гораздо проще, чем наследование и переопределение виртуальных функций ActiveX контролов. Второе выполнить просто невозможно, поскольку следует наследовать не класс с частично реализованным поведением, а интерфейсы, вообще не содержащие реализации. Если эмулировать поведение похожего класса еще возможно, то слегка переопределить его виртуальные функции - уже большая спортивная проблема. Остается разве что полностью инкапсулировать исходный класс в качестве свойства и полностью переопределять реализуемые им интерфейсы делегируя их реализацию этому инкапсулированному объекту.
Какие выводы / рекомендации можно сделать для себя? Если нужно сделать несколько объектов, которые различаются несущественно и имеют массу общего, то хорошим выбором может быть использование агрегирования свойств и изменения необходимых функций с учетом их состояния. Если архитектура программы по своему строению использует массу объектов, которые видны этой архитектуре совершенно безотносительно свойств, которыми они различаются, и методы, которыми эти объекты различаются, существенны, то скорее всего следует выбрать путь наследования.
Как можно определить, что отнести в добавляемым свойствам при агрегировании, а что к добавляемым / переопределяемым при наследовании?
Возьмем и нарисуем квадратики / кружки, соответствующие различным понятиям. В них выделим свойства и методы. После чего сгруппируем те квадратики, которые имеют общие свойства и методы. Это пересечение свойств / методов следует выделить в новый квадратик и назвать его базовым, а те квадратики, которые объединялись, назвать наследниками этого базового. И оставить в качестве дополнения к наследованным то, что не попало в пересечение. Теперь стоит вопрос - какой путь выбрать? Если оставить все как есть, то получится вариант проектирования новых классов путем наследования. Если интересует вопрос получения новых классов путем агрегирования, то квадратики следует объединить в один или более. В полученный укрупненный квадратик каждый из вошедших в него внесет что-то свое.
Следует посмотреть, можно ли часть свойств находящихся в объединении, но не находящихся в пересечении, объединить в одно или более. Являются ли они взаимоисключающими? Могут ли они представлять состояние объекта получаемого класса? Если да, то вероятность успешной агрегации весьма высока. Наличие в получаемом классе свойств и методов, возможность использования которых может зависеть не от класса объекта, а от состояния других свойств, не должна пугать. Просто надо корректно написать код обработки и в одних случаях игнорировать неправильные обращения, в других генерировать ошибку. Например, в библиотеке VCL для формы можно одновременно указать стиль заголовка и его отсутствие. Этот парадокс решается просто - если окно без заголовка, то стиль заголовка игнорируется.
При этом не следует выбирать для себя только один стиль проектирования на всю жизнь и только его и придерживаться. Это может нанести ущерб в ситуации, когда было бы лучше выбрать другой. Просто ими обоими надо владеть.