(我在此处搜索并阅读了菱形继承(钻石问题)和虚拟继承问题,但找不到答案。我的想法是这种情况有点不寻常,我愿意接受这样的想法:我的要求有所降低。另一方面,我认为这应该以“不错”的方式来实现。)

情况及要求:

我有一个C++类库,该类库无法控制,并且无法更改。它定义了一个Window类。 Window类具有 protected 成员(例如handle),该成员不能通过其他方式访问,派生类打算使用该成员。 Window定义了数百种(很多)...我不希望通过委派(例如在装饰器中)来重新实现的方法。

我想向Window添加功能,以便派生类(我写的是LogWindow)自动具有。这种功能的一个示例是能够将窗口彼此对齐。为了实现这一点,我需要访问Window的 protected handle成员。

对于我的现实生活而言,这足够了,并且解决方案很简单:从SnappableWindow派生Window,并从Window派生我所有的LogWindow派生的类(在此示例中为SnappableWindow)。

但是,我真正想要的是,更漂亮的恕我直言,是:

  • 具有此“可捕捉”功能作为独立代码段的能力,我可以选择是否“插入”任何其他Window派生的类。
  • 也可以将此概念扩展到其他功能,例如最小化窗口的能力。因此,我可以拥有一个Window派生的类,无论是否具有“可捕捉”功能,以及是否具有“最小化”功能。
  • “SnappableWindow”和“MinimizableWindow”的实现都需要访问Window的受handle保护的成员。
  • 我希望“Snappable”和“Minimizable”成为实际类声明的一部分,以便我的实际类(LogWindow)"is" Window,"is" SnappableWindow,而"is" MinimizableWindow。

  • ...现在是一个问题:

    通过声明SnappableWindowMinimizableWindow不是源自Window而是在其构造函数中获取handle,然后从LogWindow以及WindowSnappableWindow的任何组合派生MinimizableWindow,我可以获得如何做到这一点。

    编辑:handle在调用Window的init()之后,通过LogWindow的构造函数在Window中初始化。 (而不是通过Window的构造函数的一半,正如我之前所说的)。

    但是,由于handle仅通过LogWindow的构造函数进行了初始化(在它被称为Windowinit()之后),因此我无法将SnappableWindowMinimizableWindow传递为LogWindow的构造函数初始化列表的一部分。相反,我必须在两者上显式调用一些init()方法,并将其传递给handle。这是在我的每个Window派生类中。 (LogWindowSearchWindowPreferencesWindow等)

    我正在寻找一种能够执行以下操作的方法:



    ...而不必在LogWindow内实现其他任何功能。我摆弄了虚拟继承,但是还不能完全解决这个问题。

    最佳答案

    虚拟继承应该能够处理以下问题:

    class SnappableWindow: virtual public Window
    
    class MinimizableWindow: virtual public Window
    
    class LogWindow: virtual public Window, public SnappableWindow, public MinimizableWindow
    

    请注意,三角形只是钻石的特例!
    Window
    |  \  \---------------\
    |   \                  \
    |    SnappableWindow    MinimizableWindow
    |   /                  /
    |  /    /-------------/
    LogWindow
    

    编辑:这是一个完整的示例:
    #include <iostream>
    int get_handle() { static int handle = 0; return ++handle; }
    struct Window {
        int handle;
        Window() : handle(get_handle()) { }
    };
    struct SnappableWindow: virtual public Window {
        SnappableWindow() { std::cout << "Snap! " << handle << std::endl; }
    };
    struct MinimizableWindow: virtual public Window {
        MinimizableWindow() { std::cout << "Mm! " << handle << std::endl; }
    };
    struct LogWindow: virtual public Window, public SnappableWindow, public MinimizableWindow {
        LogWindow() { std::cout << "Log! " << handle << std::endl; }
    };
    int main() {
        LogWindow lw;
        std::cout << "lw: " << lw.handle << std::endl;
    }
    

    输出:
    Snap! 1
    Mm! 1
    Log! 1
    lw: 1
    

    10-06 10:34