Предположим, у меня есть архитектура некоторых классов (количество классов растет во время разработки), что каждый класс наследуется от N классов с одним и тем же базовым интерфейсом c. Как лучше всего (если возможно) создать базовую функцию (в базовом классе ИЛИ в производном классе), которая будет перебирать наследования?
Цель: Избегайте ошибок разработчиков и убедитесь, что мы не забудем вызвать все базовые функции из всех наследований и сделаем код более понятным и понятным.
См. примечания к редактированию для обновленного состояния
Краткий пример:
class shared_base {
public:
virtual void func() = 0;
}
class base_1 : virtual public shared_base {
public:
void func() override {}
}
class base_2 : virtual public shared_base {
public:
void func() override {}
}
class target : virtual public base_1, virtual public base_2 {
public:
void func() override {
// Instead of:
base_1::func();
base_2::func();
// ... My func() implementation
/*
~~TODO~~
for_each(std::begin(inheritances), std::end(inheritances), [](auto& inheritance) -> void { inheritance::func(); })
~~TODO~~
*/
}
}
Более наглядный и практический пример:
class base {
public:
virtual void func() = 0;
/*...Some interface (pure virtual) functions...*/
}
class base_core : virtual public base {
public:
void func() override {}
/*...Some base implementations for the rest...*/
protected:
template <typename FuncT>
virtual void iterate_over_base_core_inheritances(FuncT function_to_apply) {
/*~~TODO~~*/
}
}
template <class Decorator = base_core, typename = typename std::enable_if<std::is_base_of<base_core, Decorator>::value>::type>
class core_1 : virtual public Decorator {
public:
void func() override {
// Will iterate (once) over Decorator
/*iterate_over_base_core_inheritances([](core_base*) -> void {
// Implementation
});*/
// Instead of:
Decorator::func();
}
/*More functions implementations*/
}
template <class Decorator = base_core, typename = typename std::enable_if<std::is_base_of<base_core, Decorator>::value>::type>
class core_2 : virtual public core_1<>, virtual public Decorator {
public:
void func() override {
// Will iterate (twice) over core_1 and Decorator
/*iterate_over_base_core_inheritances([](core_base*) -> void {
// Implementation
});*/
// Instead of:
Decorator::func();
core_1::func();
//... Self func() implementation
}
/*More functions implementations*/
protected:
// If it's not possible doing it in the upper hierarchy level is it possible do it here?
template <typename FuncT>
void iterate_over_base_core_inheritances(FuncT function_to_apply) override {
/*~~TODO~~*/
}
}
Некоторые вещи, которые нужно знать :
- Я работаю на платформе Linux 64x (Ubuntu 16.04) - если это важно для ответов.
- Идея этого кода - создать своего рода Decorator DP, который будет легко расширять и понимать, а также позволит разработчикам использовать
protected
функции / атрибуты базового класса.
A практический пример (для моего фактического использования) можно найти в this commit .
Изменить:
Благодаря @ RaymondChen У меня есть рабочее решение, с (пока) только одним второстепенным Проблема: каждый раз, когда я хочу использовать класс, реализованный таким образом, мне нужно указать класс core_base
в его списке аргументов шаблона (раньше - я использовал параметр типа по умолчанию). Я ищу способ решить эту проблему.
Текущее решение:
template <class ...Decorators>
class core_2 : virtual public Decorators... {
public:
static_assert((std::is_base_of<base_core, Decorators>::value && ...), "All decorators must inherit from base_core class.");
void func() override {
(Decorators::func(), ...);
//... Self func() implementation
}
/*More functions implementations*/
}
Создание примера экземпляра:
Текущее:
std::shared_ptr<base> base = std::make_shared<core_2<core_1<base_core>, core_3<base_core>>>();
Желательно:
std::shared_ptr<base> base = std::make_shared<core_2<core_1<>, core_3<>>>();
A практический пример (для моего фактического использования) можно найти в этот коммит .