问题
Assume I have a some classes architecture (the number of the classes is growing up during the development time), that each class inherit from N classes with the same basic interface. What is the best way (if possible) to create a base function (in the base class OR in the derived class) that will iterate over the inheritances?
Target: Avoid developers mistakes and make sure we won't forget to call all the base functions from all of the inheritances & make the code more clear to read and understandable.
Please see edit notes for updated state
Short Example:
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~~
*/
}
}
More descriptive & practical example:
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~~*/
}
}
Some things to know:
- I am working on Linux 64x platform (Ubuntu 16.04)- if it's matter for the answers.
- The idea behind this code is to create kind of Decorator DP, which will be easy to extend and to understand, and also will enable the developers to use the
protected
functions/attributes of the base class.
A practical example (for my actual use) can be found in this commit.
Edit:
Thanks to @RaymondChen I got a working solution, with (so far) only one minor issue: Every time I want to use a class that implemented this way, I need to specify the core_base
class in it's template arguments list (before- I was using the default type parameter). I am looking for a way to solve this issue.
The current solution:
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*/
}
Creating an instance example:
Current:std::shared_ptr<base> base = std::make_shared<core_2<core_1<base_core>, core_3<base_core>>>();
Desired:std::shared_ptr<base> base = std::make_shared<core_2<core_1<>, core_3<>>>();
A practical example (for my actual use) can be found in this commit.
回答1:
Thanks to @RaymondChen I got really close to my original target with the following solution [See update section at the bottom]:
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*/
}
Explanation:
Using parameters pack we can create a "list" of classes we inherit from, and using folding expression [c++17] we can implement it in just few lines of code.
Pros compare to my original idea:
- The object creation line is more clear and logically now:
Before:std::shared_ptr<base> base = std::make_shared<core_2<core_1<core_3<>>>>();
After:std::shared_ptr<base> base = std::make_shared<core_2<core_1<base_core>, core_3<base_core>>>();
Because core_1 & core_3 are independent, but core_2 is using both of them. - No need of new function in the base/derived class, it's just fit within the target line (for example in
is_equal
function that didn't mention within this post).
Lost functionality:
- Template validation of
is_base_of
(Solved withstatic_assert
&fold expressions
). - Default inheritance in case that no inheritance specified is not possible yet (Still trying to solve).
Current:std::shared_ptr<base> base = std::make_shared<core_2<core_1<base_core>, core_3<base_core>>>();
Desired:std::shared_ptr<base> base = std::make_shared<core_2<core_1<>, core_3<>>>();
Update
After a lot of research and tries, I came up with the following solution (improved also with C++20 concepts
feature):
template <class T>
concept Decorator = std::is_base_of_v<base_core, T>;
class empty_inheritance {};
template<typename Base = base_core, typename ...Decorators>
struct base_if_not_exists {
static constexpr bool value = sizeof...(Decorators);
using type = typename std::conditional<value, empty_inheritance, Base>::type;
};
template <Decorator ...Decorators>
class core_2 : virtual public base_if_not_exists<base_core, Decorators...>::type, virtual public Decorators... {
public:
void func() override {
if constexpr (!base_if_not_exists<base_core, Decorators...>::value) {
base_core::func();
}
(Decorators::func(), ...);
//... Self func() implementation
}
/*More functions implementations*/
}
No functionality lost :)
来源:https://stackoverflow.com/questions/62091515/iterate-over-class-inheritances-in-c