У меня есть абстрактный базовый класс, который действует как интерфейс.
У меня есть два «набора» производных классов, которые реализуют половину абстрактного класса. (один «набор» определяет абстрактные виртуальные методы, связанные с инициализацией, другой «набор» определяет те, которые связаны с фактической «работой».)
Затем у меня есть производные классы, которые используют множественное наследование для создания полностью определенных классов (и ничего не добавляют сами).
Итак: (плохой псевдокод)
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
Кажется, что Виртуальное Наследование является решением здесь. Я слышал о виртуальном наследовании и раньше, но я не обернулся вокруг него. Я все еще открыт для предложений.