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

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

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

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

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

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 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() неоднозначен" при попытке использовать класс.

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

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

Edit:

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

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

Ответ 1

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


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

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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;

Ответ 4

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

Публичное наследование должно использоваться только для моделирования отношения "isa", например. собака - животное, квадрат - форма и т.д.

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

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

НТН

веселит,

Rob

Ответ 5

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

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

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