У меня есть абстрактный базовый класс, который действует как интерфейс.Множественное наследование от двух производных классов
У меня есть два «набора» производных классов, которые реализуют половину абстрактного класса. (один «набор» определяет абстрактные виртуальные методы, связанные с инициализацией, другой «набор» определяет те, которые связаны с фактической «работой».)
Затем я получил производные классы, которые используют множественное наследование для создания полностью определенных классов (и ничего не добавляет).
Итак: (плохо псевдокод)
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 как чистый интерфейс, этого можно было бы избежать (предполагая, что верный пример действителен).
So: - Я в порядке с моей реализацией? - Является ли это ограничением идиомы для создания виртуальных методов? - Как мне реорганизовать мой код, чтобы делать то, что я хочу? (Обеспечить один общий интерфейс, но позволить способ поменять реализации для «наборов» функций-членов)
Edit:
Кажется, я не первый: http://en.wikipedia.org/wiki/Diamond_problem
Кажется Virtual Наследование решение здесь. Раньше я слышал о виртуальном наследовании, но я не обворачивал его. Я по-прежнему открыт для предложений.
Это работает хорошо, даже с моими невиртуальными общественными методами. Тем не менее, мне нужно попытаться выяснить, что происходит при использовании указателя типа Base для объекта типа Derived, чтобы убедиться, что виртуальное наследование работает как перегрузка виртуальных функций :) – mmocny 2008-10-31 20:21:38
При преобразовании из виртуальной базы в производный класс вы всегда нужно использовать dynamic_cast <>, что, в свою очередь, требует, чтобы виртуальный метод был определен в виртуальной базе.Простое использование виртуальной базы не должно вызывать проблем - оно будет полиморфно предоставлять доступ к производному классу. – 2008-10-31 23:29:10