c – 如何在编译时更改类从其继承的内容?
在我创建跨平台GUI框架的过程中,我遇到了以下障碍:
假设我有一个中心的“窗口”类,在项目的一般,平台无关的包含文件夹: //include/window.hpp class Window { //Public interface } 那么我有几个平台依赖的实现类,像这样: //src/{platform}/window.hpp class WinWindow {...}; //Windows class OSXWindow {...}; //OSX class X11Window {...}; //Unix 最后,有一个原始的Window类’.cpp文件,其中我想把实现类绑定到一般类.纯粹在概念上,这就是我想要做的: //src/window.cpp //Suppose we're on Windows #include "include/window.hpp" #include "src/win/window.hpp" class Window : private WinWindow; //Redefine Window's inheritance 我知道这不是有效的C,这就是重点.我已经想到了解决这个问题的两种可能的方式,而且我有两个问题. pImpl样式实现 Make Window保存一个指向实现类的void指针,并将其分配给每个平台的不同窗口类.但是,每次我想执行平台依赖操作时,我都必须重写指针,更不用说包含依赖于平台的文件了. 预处理指令 class Window : #ifdef WIN32 private WinWindow #else ifdef X11 private X11Window //etc. 然而,这听起来更像是一个黑客,而不是解决问题的实际方法. 该怎么办?我应该完全改变我的设计吗?我的任何一种可能的解决方案都能持有一点点水? 解决方法
使用typedef隐藏预处理器
您可以简单地键入相应的窗口类型: #ifdef WINDOWS typedef WinWindow WindowType; #elif defined // etc 那么你的窗口类可以是: class Window : private WindowType { }; 这不是一个非常强大的解决方案.最好是以更加面向对象的方式思考,但C中的OO编程是运行时代价,除非你使用 好奇地重复模板模式 您可以使用好奇的重复模板模式: template<class WindowType> class WindowBase { public: void doSomething() { static_cast<WindowType *>(this)->doSomethingElse(); } }; 那你可以做 class WinWindow : public WindowBase<WinWindow> { public: void doSomethingElse() { // code } }; 并使用它(假设C 14支持): auto createWindow() { #ifdef WINDOWS return WinWindow{}; #elif UNIX return X11Window{}; #endif } 仅限C 11: auto createWindow() -> #ifdef WINDOWS WinWindow #elif defined UNIX X11Window #endif { #ifdef WINDOWS return WinWindow{}; #elif defined UNIX return X11Window{}; #endif } 我建议您使用自动,或使用它与typedef结合使用: auto window = createWindow(); window.doSomething(); 面向对象风格 你可以使你的Window类成为一个抽象类: class Window { protected: void doSomething(); public: virtual void doSomethingElse() = 0; }; 然后将依赖于平台的类定义为Window的子类.那么你所要做的就是在一个地方有预处理指令: std::unique_ptr<Window> createWindow() { #ifdef WINDOWS return new WinWindow; #elif defined OSX return new OSXWindow; // etc } 不幸的是,这通过调用虚拟函数来产生运行时代价. CRTP版本在编译时解决了对“虚拟函数”的调用,而不是在运行时调用. 此外,这需要在堆上声明窗口,而CRTP不会;这可能是一个问题,取决于用例,但一般来说,这并不重要. 最终,您必须在某个地方使用#ifdef,因此您可以确定平台(或者您可以使用确定平台的库,但也可能使用#ifdef),该问题只是隐藏它的位置. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |