Множественное наследование из двух производных classов

У меня есть абстрактный базовый class, который действует как интерфейс.

У меня есть два «набора» производных classов, которые реализуют половину абстрактного classа. (один «набор» определяет абстрактные виртуальные методы, связанные с инициализацией, другой «набор» определяет те, которые связаны с фактической «работой».)

Затем я получил производные classы, которые используют множественное наследование для создания полностью определенных classов (и ничего не добавляют).

Итак: (плохой псевдокод)

class AbsBase { virtual void init() = 0; virtual void work() = 0; } class AbsInit : public AbsBase { void init() { do_this(); } // work() still abs } class AbsWork : public AbsBase { void work() { do_this(); } // init() still abs } class NotAbsTotal : public AbsInit, public AbsWork { // Nothing, both should be defined } 

Прежде всего, могу ли я это сделать? Могу ли я наследовать от двух classов, которые оба получены из одной базы? (Я надеюсь, что это так).

Вот «реальная проблема», хотя (я чуть-чуть лгал, чтобы упростить пример).

То, что я действительно сделал, – это добавить методы абстрактного доступа к базовому classу:

 class AbsBase { public: void init() { init_impl(); } void work() { work_impl(); } private: virtual void init_impl() = 0; virtual void work_impl() = 0; } 

Потому что общая идиома заключается в том, чтобы сделать все виртуальные методы частными.

К сожалению, теперь и AbsInit, и AbsWork наследуют эти методы, и поэтому NotAbsTotal наследует «два из каждого» (я понимаю, что я могу разбить то, что действительно происходит во время компиляции).

Во всяком случае, g ++ жалуется, что: «запрос для члена init () неоднозначен» при попытке использовать class.

Я предполагаю, что, если бы я использовал свой class AbsBase как чистый интерфейс, этого можно было бы избежать (предполагая, что верхний пример действителен).

Итак: – Я сработал с моей реализацией? – Является ли это ограничением идиомы для создания виртуальных методов? – Как мне реорганизовать мой код, чтобы делать то, что я хочу? (Предоставьте один общий интерфейс, но дайте возможность поменять местами реализации «наборов» функций-членов)

Редактировать:

Кажется, я не первый: http://en.wikipedia.org/wiki/Diamond_problem

Кажется, что Virtual Inheritance является решением здесь. Раньше я слышал о виртуальном наследовании, но я не обворачивал его. Я по-прежнему открыт для предложений.

Похоже, вы хотите сделать виртуальное наследование. На самом деле это хорошая идея, это еще один вопрос, но вот как вы это делаете:

 class AbsBase {...}; class AbsInit: public virtual AbsBase {...}; class AbsWork: public virtual AbsBase {...}; class NotAbsTotal: public AbsInit, public AbsWork {...}; 

По сути, не виртуальное множественное наследование будет включать в себя копию каждого базового classа в производном classе и включает все их методы. Вот почему у вас есть две копии AbsBase – и причина, по которой ваш метод используется, неоднозначна, загружаются оба набора методов, поэтому C ++ не имеет способа узнать, какая копия для доступа!

Виртуальное наследование конденсирует все ссылки на виртуальный базовый class в одну структуру данных. Это должно снова сделать методы из базового classа однозначными. Однако обратите внимание: если в двух промежуточных classах есть дополнительные данные, может возникнуть небольшая дополнительная накладная часть времени выполнения, чтобы код мог найти общий виртуальный базовый class.

Вам нужно объявить наследование виртуальным:

 struct AbsBase { virtual void init() = 0; virtual void work() = 0; }; struct AbsInit : virtual public AbsBase { void init() { } }; struct AbsWork : virtual public AbsBase { void work() { } }; struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork { }; void f(NotAbsTotal *p) { p->init(); } NotAbsTotal x; 

Это можно сделать, хотя это дает большую часть дрожь.

Вам нужно использовать «виртуальное наследование», синтаксис для чего-то вроде

 class AbsInit: public virtual AbsBase {...}; class AbsWork: public virtual AbsBase {...}; class NotAbsTotal: public AbsInit, public AbsWork {...}; 

Затем вы должны указать, какую функцию вы хотите использовать:

 NotAbsTotal::work() { AbsInit::work_impl(); } 

(ОБНОВЛЕНО с правильным синтаксисом)

Вы должны начать думать в терминах того, что вы пытаетесь моделировать здесь.

Публичное наследование должно использоваться только для моделирования отношений «isa», например, собака – это животное, квадрат – это форма и т. Д.

Взгляните на книгу Скотта Мейера «Эффективный С ++» для отличного эссе о том, какие аспекты дизайна ОО следует только интерпретировать.

Редактирование: я забыл сказать, что, хотя предоставленные до сих пор ответы технически правильны, я не думаю, что кто-либо из них решает проблемы того, что вы пытаетесь моделировать, и в этом суть вашей проблемы!

НТН

веселит,

обкрадывать

Я нашел хороший и простой пример в приведенной ниже ссылке. В статье объясняется примерная программа для расчета площади и периметра прямоугольника. Вы можете проверить это.

Многоуровневое наследование – это иерархия наследования, в которой один производный class наследуется от нескольких базовых classов. Прочитайте больше..

http://www.mobihackman.in/2013/09/multiple-inheritance-example.html

  • Может ли интерфейс расширять несколько интерфейсов в Java?
  • Инициализировать защищенные члены родителя с помощью списка инициализации (C ++)
  • Поведение статических блоков с наследованием
  • C ++ Доступный элемент classа из указателя базового classа
  • Преобразование указателя в указатель между производными и базовыми classами?
  • Ошибка C #: родительский элемент не содержит конструктор, который принимает 0 аргументов
  • Реализует vs extends: Когда использовать? Какая разница?
  • Должен ли я избегать многозадачного (конкретного) наследования в Django любыми способами?
  • JSP-трюки, чтобы упростить создание шаблонов?
  • Преобразовать список в список
  • Почему classы java не наследуют annotations от реализованных интерфейсов?
  • Давайте будем гением компьютера.