#c #multiple-inheritance
#c #множественное наследование
Вопрос:
У меня есть 3 класса, A
, B
, и C
где B
an A
и C
является an A
.
Эти классы предназначены для сохранения истории, поэтому A
предоставляют виртуальный метод, который производные классы могут создавать, чтобы получать уведомления, когда история должна быть заархивирована, вызывается void archive()
.
Теперь внезапно возникает необходимость получить информацию из A
, B
, и C
в одном классе, и я не уверен, что это лучший подход.
Я подумал о создании нового класса D
, который наследует от B
and C
, и изменил их наследование virtual public A
, чтобы избежать проблемы с бриллиантами и D::archive()
просто вызвать B::archive()
and C::archive()
.
Это хороший подход? Или я должен перепроектировать 4 класса таким образом, чтобы я не использовал множественное наследование?
Комментарии:
1.
Now suddenly there is a need to have the information from A, B, and C in a single class
— это корень зла. Чего именно вы пытаетесь достичь?2. Информация в
B
иC
очень различна, и никогда не думали или не представляли себе необходимость во всех 3 классах информации. Но, конечно, пару лет спустя кому-то в голову пришла «крутая» идея, и интерфейс не работает, поэтому я пытаюсь найти наилучший подход к изменению этого.3. Трудно рассуждать об этом абстрактно. В общем, вы можете рассматривать композицию как альтернативу наследованию, но это зависит от специфики. MI может быть хорошим, когда это уместно.
Ответ №1:
Ваш подход является стандартным. C имеет множественное наследование, и вы должны чувствовать себя свободно использовать его. Похоже, вы знаете, как это сделать правильно.
Комментарии:
1. Это облегчение слышать. Я стараюсь избегать множественного наследования, насколько это возможно, и потребовалось некоторое время, чтобы правильно понять этот подход, поэтому я хотел убедиться, что я ничего не пропустил, прежде чем изменять весь код.
2. Кстати, другие предложенные подходы тоже действительны, но я предполагаю, что вам нужна иерархия для полиморфизма, и вы не хотите менять все это только для этого. Начиная с нуля, вы можете вместо этого рассмотреть смешивание интерфейсов (и композицию для повторного использования кода), но то, что вы рассматриваете, тоже нормально.
Ответ №2:
Как насчет использования композиции вместо этого?
Например. class D
делегирует классам B
и C
вместо наследования.
Композиция может достигать тех же результатов, а код намного проще (ИМХО)
Ответ №3:
Остерегайтесь цепочки вызовов, которые могут иметь возможные методы переопределения: если B::method
вызовы A::method
и C::method
вызовы A::method
, когда вы объединяете их в D, делая виртуальным, если D::method
вызывает оба C::method
и B::method
, вас A::method
вызывают дважды.
Когда база становится виртуальной, вы должны избегать таких повторных входов.
Ответ №4:
Вы могли бы иметь D, полученный из A, содержащий два члена B и C. D::archive вызовет B::archive и C::archive