【问题标题】:Iterate over class inheritances in C++迭代 C++ 中的类继承
【发布时间】:2020-05-29 17:27:59
【问题描述】:

假设我有一些类架构(类的数量在开发过程中不断增加),每个类都继承自 N 个具有相同基本接口的类。创建将迭代继承的基函数(在基类或派生类中)的最佳方法是什么(如果可能)?

目标:避免开发人员错误,确保我们不会忘记从所有继承中调用所有基本函数,并使代码更清晰易读。

请查看更新状态的编辑说明

简短示例:

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 函数/属性。

一个实际例子(供我实际使用)可以在this commit找到。

编辑:

Thanks to @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&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;base_core&gt;, core_3&lt;base_core&gt;&gt;&gt;();
所需:
std::shared_ptr&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;&gt;, core_3&lt;&gt;&gt;&gt;();

一个实际例子(供我实际使用)可以在this commit找到。

【问题讨论】:

  • template&lt;typename...inheritances&gt; struct Decorator : virtual inheritances... { void func() override { (inheritances::func(), ...); } };
  • @RaymondChen 非常感谢!请将其发布为答案。
  • 没关系,你可以在充实之后发布答案(并接受它)。我不需要虚点。
  • @RaymondChen 经过大量研究,我能够恢复没有可变参数模板的所有功能(请参阅我回复中的编辑部分)。非常感谢您的帮助!

标签: c++ variadic-templates multiple-inheritance crtp fold-expression


【解决方案1】:

感谢@RaymondChen,通过以下解决方案,我已经非常接近最初的目标 [请参阅底部的更新部分]:

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*/
}

解释:

使用参数包我们可以创建一个我们继承自的类的“列表”,并且使用折叠表达式 [c++17] 我们可以在几行代码中实现它。

优点与我最初的想法相比:

  • 对象创建线现在更加清晰和合乎逻辑:
    之前:
    std::shared_ptr&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;core_3&lt;&gt;&gt;&gt;&gt;();
    之后:
    std::shared_ptr&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;base_core&gt;, core_3&lt;base_core&gt;&gt;&gt;();
    因为 core_1 和 core_3 是独立的,但是 core_2 都在使用它们。
  • 基类/派生类中不需要新函数,它只适合目标行(例如在本文中未提及的is_equal 函数中)。

功能丢失:

  • is_base_of 的模板验证(已通过 static_assert 和 fold expressions 解决)。
  • 如果尚未指定继承,则默认继承是不可能的(仍在尝试解决)。
    当前:
    std::shared_ptr&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;base_core&gt;, core_3&lt;base_core&gt;&gt;&gt;();
    期望:强>
    std::shared_ptr&lt;base&gt; base = std::make_shared&lt;core_2&lt;core_1&lt;&gt;, core_3&lt;&gt;&gt;&gt;();

更新

经过大量研究和尝试,我想出了以下解决方案(还通过 C++20 concepts 功能进行了改进):

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*/
}

没有功能丢失:)

【讨论】:

  • 我不明白这个解决方案如何使您的代码更易于阅读?
  • @Moo-Juice 与我在问题中建议的解决此问题的最初方式相比,我不需要更多的函数/循环,只需一行代码 (Decorators::func(), ...) 或 return (Decorators::is_equal(...) &amp;&amp; ...) &amp;&amp; /*local function equality tests*/; .使用接受模板函数参数的分层函数很容易让事情变得非常复杂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2016-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-17
相关资源
最近更新 更多