0

我为所有继承的应用程序编写了几个窗口Gtkmm::Window。在这一点上,我想自动化这个过程。现在,以下结构脱颖而出:

class MyWindow : public Gtk::Window
{
public:
    MyWindow();
    virtual ~MyWindow();

    //...

private:
    void registerLayouts(); // Adds layouts to the window.
    void registerWidgets(); // Adds widgets to the layouts.

    //...
};

和构造函数:

MyWindow::MyWindow()
{
    registerLayouts(); // Cannot be virtual: in constructor.
    registerWidgets(); // Cannot be virtual: in constructor.

    //...
}

所以问题是,每次必须对新窗口进行编程时,所有这些都必须手动完成(即复制/粘贴),因为registerLayouts()registerWidgets()在构造时被调用,因此不能virtual

理想情况下,我将有一个可以继承的基类,它可以让我选择覆盖这两个方法并处理其余部分:它将在适当的位置调用这两个方法。

问题是,我还没有找到这个合适的位置。我看过不同的信号处理程序,但似乎没有。

你知道我该怎么做吗?

MFC 具有CDialog::OnInitDialog()执行类似于我需要的功能的功能。

4

1 回答 1

1

您可以将工作委托给一个单独的类:

class MyWindow : public Gtk::Window
{
//public:  *** EDIT ***
protected:
    template <typename LayoutManager>
    MyWindow(LayoutManager const& lm)
    {
        lm.registerLayouts(this);
        lm.registerWidgets(this);
    }
};

class SubWindow : public MyWindow
{
    class LM { /* ... */ };
public:
     SubWindow() : MyWindow(LM()) { }
};

(编辑:改进的模式隐藏了子类的布局管理器......)

或者,整个类作为模板(可能优于上述)

template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
public:
    MyWindow()
    {
        LayoutManager lm(*this);
        lm.registerLayouts();
        lm.registerWidgets();
    }
};

class SpecificLayoutManager { /* ... */ };
using SpecificWindow = MyWindow<SpecificLayoutManager>;

如果您还需要布局管理器进行清理(我自己不熟悉 GTK...):

template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
    LayoutManager lm;
public:
    MyWindow() : lm(*this)
    {
        lm.registerLayouts();
        lm.registerWidgets();
    }
    virtual ~MyWindow()
    {
        // still access to lm...
    }
};

重要说明:在所有变体中,我们还没有完全构造的派生类——因此在布局管理器中转换为后者是不合法的(用奇怪的重复模板模式进行实验,但出于完全相同的原因放弃了这个想法:需要也可以在基的构造函数中转换为派生)。

根据评论进行编辑:关于如何管理子类的其他成员的示例(使用上面的第三个变体,模板类之一与布局管理器成员;lm成员现在需要是protected):

class SubWindowLayoutManager
{
    template <typename>
    friend class MyWindow;
    friend class SubWindow;

    int someMember;

    void registerLayouts() { }
    void registerWidgets() { }

};
class SubWindow : public MyWindow<SubWindowLayoutManager>
{
    void doSomething()
    {
        lm.someMember = 77;
    }
};

另外一个完全没有模板的新变体:

class MyWindow : public Gtk::Window
{
protected:
    class LayoutManager
    {
    public:
         virtual void registerLayouts(MyWindow* parent) = 0;
         virtual void registerWidgets(MyWindow* parent) = 0;
    };

    std::unique_ptr<LayoutManager> lm;

    MyWindow(std::unique_ptr<LayoutManager> lm)
        : lm(std::move(lm))
    {
        this->lm->registerLayouts(this);
        this->lm->registerWidgets(this);
    }
};

class SubWindow : public MyWindow
{
    class LM : public LayoutManager
    {
    public:
        void registerLayouts(MyWindow* parent) override { }
        void registerWidgets(MyWindow* parent) override { }

        int someMember;
    };

    // convenience access function:
    inline LM& lm()
    {
        return *static_cast<LM*>(MyWindow::lm.get());
    }

public:
    SubWindow() : MyWindow(std::make_unique<LM>()) { }

    void doSomething()
    {
        //static_cast<LM*>(lm.get())->someMember = 77;
        lm().someMember = 77;
    }
};
于 2018-09-11T11:43:01.140 回答