首页 > 解决方案 > 直接访问类接口中成员的成员,无需继承

问题描述

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

这应该概述我的问题(见下面的代码):我希望我从用户的角度class Widget包含界面。class WidgetSignals我不能使用继承,因为这需要我在应该用来初始化WidgetSignals的成员之前初始化继承。elementsWidgetWidgetSignals

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)
    {}
};

在 Widget 中封装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
};

通过这两种解决方案,我可以WidgetSignals通过 a使用接口Widget

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

但是这两个解决方案都相当笨拙和混乱,所以我真的很想有一个更好的语法,比如:

using signals;

或者

using signals::enter;

Widget. using WidgetSignals<Elems...>::enter;实际上是可行的,但前提是Widget已经继承自WidgetSignals,这意味着我必须再次使用调解器助手类,我想避免这种情况。

标签: c++inheritanceconstructorc++14member

解决方案


只需将您要首先初始化的元素粘贴到您首先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首先初始化基础:如果WdigetSignalsvirtual基础,则可能需要将 a 粘贴virtualWidgetPbase.


推荐阅读