c – 如何在编译时更改类从其继承的内容?

前端之家收集整理的这篇文章主要介绍了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),该问题只是隐藏它的位置.

原文链接:https://www.f2er.com/c/114131.html

猜你在找的C&C++相关文章