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

Directly access members of members in a class interface without inheritance

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

这应该概述了我的问题(见下面的代码):我希望我的 class Widget 从用户的角度包括 class WidgetSignals 的界面。我不能使用继承,因为这需要我在 Widget 的成员 elements 之前初始化继承的 WidgetSignals 应该用于初始化 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))
};

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

使用中介助手class:

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 并在 Widget:

中公开对 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:

使用 WidgetSignals 的界面
Widget widget(vec4(0, 0, 20, 5));
foo(widget.enter);

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

using signals;

using signals::enter;

Widget 中。 using WidgetSignals<Elems...>::enter; 实际上是可行的,但前提是 Widget 已经继承自 WidgetSignals,这意味着我必须再次使用中介助手 class,我希望如此避免。

只需将您要首先初始化的元素粘贴到您首先继承的 [private] 基础 class 中。例如:

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

As base classes as inherited left-to-right/top-to-bottom 这安排 elements 成员在访问时初始化。唯一可能需要注意的是 virtual 碱基首先被初始化:如果 WdigetSignals 是一个 virtual 碱基,可能需要在 WidgetPbase 前面加上一个 virtual .