Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++&引用;三角形“;(而不是钻石)继承权_C++_Design Patterns_Generic Programming_Virtual Inheritance - Fatal编程技术网

C++ C++&引用;三角形“;(而不是钻石)继承权

C++ C++&引用;三角形“;(而不是钻石)继承权,c++,design-patterns,generic-programming,virtual-inheritance,C++,Design Patterns,Generic Programming,Virtual Inheritance,(我在这里搜索并阅读了钻石和虚拟继承问题,但找不到答案。我认为这种情况有点不寻常,我愿意接受我的要求有点偏离的想法。另一方面,我认为这应该是一种“好”的方式。) 情况和要求: 我有一个C++类库,我无法控制它,我不能改变它。它定义了一个窗口类。窗口类有一个派生类要使用的受保护成员(例如:句柄),该成员不可访问窗口定义了数百个(嗯,非常多的…)方法,我不想通过委托(比如在装饰器中)来重新实现这些方法 我想将功能添加到窗口,以便派生类(我编写的;比如LogWindow)自动具有。这种功能的一个例子是

(我在这里搜索并阅读了钻石和虚拟继承问题,但找不到答案。我认为这种情况有点不寻常,我愿意接受我的要求有点偏离的想法。另一方面,我认为这应该是一种“好”的方式。)

情况和要求:

<>我有一个C++类库,我无法控制它,我不能改变它。它定义了一个
窗口
类。
窗口
类有一个派生类要使用的受保护成员(例如:
句柄
),该成员不可访问<代码>窗口定义了数百个(嗯,非常多的…)方法,我不想通过委托(比如在装饰器中)来重新实现这些方法

我想将功能添加到
窗口
,以便派生类(我编写的;比如
LogWindow
)自动具有。这种功能的一个例子是能够将窗口彼此捕捉。为了实现这一点,我需要访问
窗口
的受保护
句柄
成员

对于我的现实生活来说,这就足够了,解决方案也很简单:从
Window
派生
snappableindow
,并从
snappableindow
派生所有
Window
派生的类(
LogWindow

然而,我真正想要的,也是更漂亮的IMHO,是:

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

    我知道如何将
    SnappableWindow
    MinimizableWindow
    声明为不是从
    Window
    派生的,而是在其构造函数中获得
    句柄
    来实现这一点,然后从
    Window
    SnappableWindow
    minimablewindow
    的任意组合中导出
    LogWindow

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

    然而,由于
    handle
    只是通过
    LogWindow
    的构造函数(在调用
    Window
    init()
    之后)初始化了一半,所以我不能将is作为
    LogWindow
    的构造函数初始化列表的一部分传递给
    SnappableWindow
    minimablewindow
    。相反,我必须显式地对这两种方法调用一些
    init()
    方法,并将
    句柄传递给它。在我的每个
    窗口中
    派生的类中。(
    日志窗口
    搜索窗口
    首选项窗口
    等)

    我正在寻找一种方法来做一些事情,比如:

    类LogWindow:公共窗口、公共SnappableWindow、公共最小化窗口


    。。。并且不必在
    LogWindow
    中实现任何其他功能。我已经摆弄过虚拟继承,但还没有找到解决方案。

    这实际上有点让人困惑。。。如果句柄作为
    窗口
    构造函数的一部分初始化,则在初始化器列表中
    窗口
    构造函数完成后,句柄将可用:

    class Window {
    protected:
       int handle;
       Window() { handle = 5; }
    };
    struct Snappable {
       int hdl;
       Snappable( int handle ) : handle(handle) {}
    };
    struct MyWindow : Window, Snappable {       // Order matters here!
       MyWindow() : Window(), Snappable( handle ) {}
    };
    int main() {
       MyWindow w;
       std::cout << w.hdl << std::endl;         // 5
    }
    
    类窗口{
    受保护的:
    int句柄;
    Window(){handle=5;}
    };
    结构可捕捉{
    int-hdl;
    可捕捉(int句柄):句柄(句柄){}
    };
    struct MyWindow:Window,可捕捉{//这里的顺序很重要!
    MyWindow():Window(),可捕捉(句柄){}
    };
    int main(){
    我的窗口w;
    
    std::cout虚拟继承应该能够处理以下问题:

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

    您可以使用traits,但不幸的是,它们无法访问受保护的成员。如果您创建一个公开受保护成员的中间类,您可以这样做。请查看它是否有意义:

    struct Window {
    protected:
        int handle;
    };
    struct BaseWindow : public Window {
        int get_handle() { return handle; }
    };
    template <class TWindow>
    struct Snappable {
        Snappable() { std::cout << "Snappable " << self()->get_handle() << std::endl; }
    private:
        TWindow *const self() {
            return static_cast<TWindow*>(this);
        }
    };
    template <class TWindow>
    struct Minimizable {
        Minimizable() { std::cout << "Minimizable " << self()->get_handle() << std::endl; }
    private:
        TWindow *const self() {
            return static_cast<TWindow*>(this);
        }
    };
    struct LogWindow: public BaseWindow, public Snappable<LogWindow>, public Minimizable<LogWindow> {
    };
    
    struct窗口{
    受保护的:
    int句柄;
    };
    结构BaseWindow:公共窗口{
    int get_handle(){return handle;}
    };
    模板
    结构可捕捉{
    
    可捕捉的{std::cout也许你至少可以在Windows上看一看,WTL已经非常类似于你试图做的事情。由于派生构造函数只在基类构造函数完成后运行,所以在基类构造函数的中途初始化句柄应该不会引起问题。很抱歉,在描述re“handle”已初始化。我编辑了原始问题。谢谢,这样做了。我的问题是,我没有在LogWindow类中从Window虚拟派生。我确实从Window虚拟派生SnappableWindow。我想这基本上回答了这个问题。你会说这是“很好”吗还有一种被接受的模式?还有什么其他/更好的方法可以做到这一点?@NitzanShaked虚拟继承是绝对好的;重要的是要理解基类偏移量是在运行时应用的,这样会对性能造成较小的影响,并与改进的二进制兼容性相平衡。Jordão建议在运行时使用CRTP更有效s基类偏移量在编译时烘焙;
    struct Window {
    protected:
        int handle;
    };
    struct BaseWindow : public Window {
        int get_handle() { return handle; }
    };
    template <class TWindow>
    struct Snappable {
        Snappable() { std::cout << "Snappable " << self()->get_handle() << std::endl; }
    private:
        TWindow *const self() {
            return static_cast<TWindow*>(this);
        }
    };
    template <class TWindow>
    struct Minimizable {
        Minimizable() { std::cout << "Minimizable " << self()->get_handle() << std::endl; }
    private:
        TWindow *const self() {
            return static_cast<TWindow*>(this);
        }
    };
    struct LogWindow: public BaseWindow, public Snappable<LogWindow>, public Minimizable<LogWindow> {
    };