Множественное наследование от двух производных классов - PullRequest
26 голосов
/ 31 октября 2008

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

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

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

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

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

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

Ответы [ 5 ]

35 голосов
/ 31 октября 2008

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


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

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

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

1 голос
/ 31 октября 2008

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

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;
1 голос
/ 31 октября 2008

Это можно сделать, хотя больше всего дрожит.

Вам необходимо использовать «виртуальное наследование», синтаксис которого выглядит примерно так:

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

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

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

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

0 голосов
/ 03 сентября 2013

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

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

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

0 голосов
/ 01 ноября 2008

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

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

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

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

НТН

ура

Rob

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...