C++ C++&引用;三角形“;(而不是钻石)继承权
(我在这里搜索并阅读了钻石和虚拟继承问题,但找不到答案。我认为这种情况有点不寻常,我愿意接受我的要求有点偏离的想法。另一方面,我认为这应该是一种“好”的方式。) 情况和要求: <>我有一个C++类库,我无法控制它,我不能改变它。它定义了一个C++ C++&引用;三角形“;(而不是钻石)继承权,c++,design-patterns,generic-programming,virtual-inheritance,C++,Design Patterns,Generic Programming,Virtual Inheritance,(我在这里搜索并阅读了钻石和虚拟继承问题,但找不到答案。我认为这种情况有点不寻常,我愿意接受我的要求有点偏离的想法。另一方面,我认为这应该是一种“好”的方式。) 情况和要求: 我有一个C++类库,我无法控制它,我不能改变它。它定义了一个窗口类。窗口类有一个派生类要使用的受保护成员(例如:句柄),该成员不可访问窗口定义了数百个(嗯,非常多的…)方法,我不想通过委托(比如在装饰器中)来重新实现这些方法 我想将功能添加到窗口,以便派生类(我编写的;比如LogWindow)自动具有。这种功能的一个例子是
窗口
类。窗口
类有一个派生类要使用的受保护成员(例如:句柄
),该成员不可访问<代码>窗口定义了数百个(嗯,非常多的…)方法,我不想通过委托(比如在装饰器中)来重新实现这些方法
我想将功能添加到窗口
,以便派生类(我编写的;比如LogWindow
)自动具有。这种功能的一个例子是能够将窗口彼此捕捉。为了实现这一点,我需要访问窗口
的受保护句柄
成员
对于我的现实生活来说,这就足够了,解决方案也很简单:从Window
派生snappableindow
,并从snappableindow
派生所有Window
派生的类(LogWindow
)
然而,我真正想要的,也是更漂亮的IMHO,是:
窗口
派生类窗口
派生类,有或没有“可捕捉”功能,有或没有“可最小化”功能Window
的handle
受保护的成员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> {
};