У меня есть абстрактный базовый класс, который действует как интерфейс.
У меня есть два «набора» производных классов, которые реализуют половину абстрактного класса. (один «набор» определяет абстрактные виртуальные методы, связанные с инициализацией, другой «набор» определяет методы, связанные с фактической «работой».)
Затем я создал производные классы, которые используют множественное наследование для создания полностью определенных классов (и сами ничего не добавляют).
Итак: (плохой псевдокод)
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 как чистый интерфейс, этого можно было бы избежать (при условии, что верхний пример верен).
Итак: - Я ошибаюсь со своей реализацией? - Это ограничение идиомы делать виртуальные методы приватными? - Как мне провести рефакторинг моего кода, чтобы сделать то, что я хочу? (Предоставляет один общий интерфейс, но позволяет заменять реализации на «наборы» функций-членов)
Изменить:
Кажется, я не первый: http://en.wikipedia.org/wiki/Diamond_problem
Кажется, решение здесь - виртуальное наследование. Я слышал о виртуальном наследовании и раньше, но еще не стал думать о нем. Я все еще открыт для предложений.
Почему ты так говоришь? Каковы последствия виртуального наследования, помимо сложности синтаксиса?
– mmocny31 октября 2008, 19:51Преобразование базового указателя в производный класс обычно включает корректировку указателя с использованием динамической таблицы поиска. Это дополнительное косвенное обращение приводит к стоимости преобразования базового значения в производное. При вызове виртуального метода эти накладные расходы связаны с шумом вызова.
– Martin v. Löwis31 октября 2008, 23:32