代码之家  ›  专栏  ›  技术社区  ›  stimulate

直接访问类接口中成员的成员而不继承

  •  3
  • stimulate  · 技术社区  · 6 年前

    我面临的问题是,在我的应用程序中,在构造函数中初始化类成员的顺序很重要。因此,我需要使用笨拙的语法来获得我想要的行为。

    这应该概述我的问题(见下面的代码):我想要我的 class Widget 包括 class WidgetSignals 从用户的角度来看。我不能使用继承,因为这需要我初始化继承的 WidgetSignals 在成员面前 elements Widget WidgetSignals公司 .

    template<typename... Elems>
    class WidgetSignals
    {
        WidgetSignals(const std::tuple<Elems...> elems)
            : // initialize members using elems
        {}
        // members ...
    };
    
    template<typename... Elems>
    class Widget : public WidgetSignals<Elems...>
    {
        std::tuple<Elems...> elements;
    
        Widget(vec4 quad)
            : WidgetSignals<Elems...>(elements) // uh-oh! elements are not initialized yet!
            , elements(initalizeElements(quad))
    };
    

    下面是我以前解决这个问题的方法:

    使用中介帮助程序类:

    template<typename... Elems>
    class Widget : public WidgetSignals<Elems...>
    {
        std::tuple<Elems...> elements;
    
        struct Data
        {
            Data(vec4 quad)
                : elems(initializeElements(quad))  // initialize elements here
            {}        
            std::tuple<Elems...> elems;
        };
        Widget(Data data)
            : WidgetSignals<Elems...>(data.elems) // bingo!
            , elements(data.elems)
        {}
    };
    

    封装 WidgetSignals公司 WidgetSignals公司 '小部件中的成员:

    template<typename... Elems>
    class Widget
    {
        std::tuple<Elems...> elements;
        WidgetSignals<Elems...> signals;
    
        Widget(vec4 quad)
            : elements(initializeElements(quad))
            , signals(elements) // initialized after elements because of order of member declaration
        {}
        // WidgetSignal member references
        const typename WidgetSignals<Elems...>::SignalType& enter = signals.enter;
        const typename WidgetSignals<Elems...>::SignalType& leave = signals.leave;
        // ... remaining members
    };
    

    有了这两个解决方案,我就可以使用 通过一个 小装置

    Widget widget(vec4(0, 0, 20, 5));
    foo(widget.enter);
    

    但这两种解决方案都相当繁琐和混乱,所以我真的希望有更好的语法,比如:

    using signals;
    

    using signals::enter;
    

    小装置 . using WidgetSignals<Elems...>::enter; 实际上是有效的,但前提是 已经继承自 WidgetSignals公司

    1 回复  |  直到 6 年前
        1
  •  3
  •   Dietmar Kühl    6 年前

    只需将要初始化的元素粘贴到[ private ]从第一个继承的基类。例如:

    template<typename... Elems>
    struct WidgetPbase {
        std::tuple<Elems...> elements;
    }
    template<typename... Elems>
    class Widget
        : private WidgetPbase<Elems...>
        , public WidgetSignals<Elems...>
    {
    public:
        Widget(vec4 quad)
            : WidgetPbase<Elems...>{initializeElements(quad)}
            , WidgetSignals<Elems...>(elements) {
        }
    };
    

    elements 要在访问时初始化的成员。唯一可能的警告是 virtual 底座先初始化:如果 WdigetSignals 事实上的 可能有必要粘上 事实上的 WidgetPbase .