Iterate over class inheritances in C++

元气小坏坏 提交于 2021-01-28 14:02:08

问题


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 with static_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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!