最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - How to implement abstractionencapsulation; like a genericopaque struct that holds a platform specific window - Stack Overflo

programmeradmin6浏览0评论
typedef struct 
{
    WindowData data;
    bool vsync;
} Window;

typedef struct
{
    Window window;
    GLFWwindow *native_window;
} WindowsWindow;

Window *windowCreate(const WindowProperties props, Handle id)
{
    WindowsWindow *windows_window = malloc(sizeof(WindowsWindow));
    *windows_window = windowswindowCreate(props);
    glfwSetWindowUserPointer(windows_window->native_window, &windows_window->window.data);
    Window *window = (Window *)windows_window;
    window->data.id = id;
    return window;
}

void windowSetContextCurrent(Window *window)
{
    //log_info("Window Context current, %s", window->data.props.name);
    glfwMakeContextCurrent(((WindowsWindow *)window)->native_window);
}

So This is a little snippet that hopefully conveys what I was doing before. I was casting the platform-specific window to the generic window pointer then would convert the generic pointer when needed to the platform-specific one to access its platform-specific data (just the native window currently) and I have run into the issue now of my alignment being off now specifically in my Nuklear GUI layer causing an error when deleting the window the ID of the window accesses the width of the window now instead of the windows ID (its index in my array of all windows) so I access the index at 800 instead of 0.

So lesson learned don't have a pointer point to a pointer of a different type (maybe some good use cases but definitely not here). Is there a better method to do this?

typedef struct 
{
    WindowData data;
    bool vsync;
} Window;

typedef struct
{
    Window window;
    GLFWwindow *native_window;
} WindowsWindow;

Window *windowCreate(const WindowProperties props, Handle id)
{
    WindowsWindow *windows_window = malloc(sizeof(WindowsWindow));
    *windows_window = windowswindowCreate(props);
    glfwSetWindowUserPointer(windows_window->native_window, &windows_window->window.data);
    Window *window = (Window *)windows_window;
    window->data.id = id;
    return window;
}

void windowSetContextCurrent(Window *window)
{
    //log_info("Window Context current, %s", window->data.props.name);
    glfwMakeContextCurrent(((WindowsWindow *)window)->native_window);
}

So This is a little snippet that hopefully conveys what I was doing before. I was casting the platform-specific window to the generic window pointer then would convert the generic pointer when needed to the platform-specific one to access its platform-specific data (just the native window currently) and I have run into the issue now of my alignment being off now specifically in my Nuklear GUI layer causing an error when deleting the window the ID of the window accesses the width of the window now instead of the windows ID (its index in my array of all windows) so I access the index at 800 instead of 0.

So lesson learned don't have a pointer point to a pointer of a different type (maybe some good use cases but definitely not here). Is there a better method to do this?

Share Improve this question edited Mar 23 at 19:58 desertnaut 60.5k32 gold badges155 silver badges181 bronze badges asked Mar 23 at 19:02 AidanAidan 895 bronze badges 14
  • 2 Aside: I hope you can work out some better nomenclature than Window *window = (Window *)windows_window;. – Weather Vane Commented Mar 23 at 19:06
  • @WeatherVane whats wrong with it? – Aidan Commented Mar 23 at 19:18
  • 1 When window in some variation of upper/lower case, single/plural/underscore etc appears so many times in every line, it's not exactly easy to read. – Weather Vane Commented Mar 23 at 19:21
  • @WeatherVane I see your point but how else would you label a window that is Windows specific kind of hard to get around it like if it was a linux window it would be linux_window. I guess win_window would work better I just liked to keep the full name – Aidan Commented Mar 23 at 19:41
  • 1 Do you really need runtime abstraction if you're working on a specific platform? I mean what's the point of a linux window on a non-linux platform? Wouldn't it be better to implement static polymorphism (e.g. using the preprocessor to generate platform specific code)? Do i miss something here? Btw, GLFW is already platform agnostic, so why the effort!? – Erdal Küçük Commented Mar 24 at 2:19
 |  Show 9 more comments

1 Answer 1

Reset to default 1

The canonical approach to this is to have a struct containing all the data that's common to the types, and a union inside it that has one of the OS-specific versions.

There are two main ways to let it know which version it's looking at: first is to have a type field in the struct that other functions can look at to decide which element of the union to use. The other is to have all the functionality that's specific to one OS wrapped in a function, and then set up function pointers to the correct versions when you initialize the struct.

And you can always combine the two: function pointers for the differences that are worth having in their own function, and a type var for the rest.

Option 1: enum

enum Window_Type { WINDOWS, X11 };

typedef struct {
    /* enum to tell us which element of the union to use. All functions that operate on a Window
     * will check this first to see which branch to take/auxiliary function to call.
     */
    enum Window_Type type;

    //common data
    unsigned id;
    bool vsync;

    //OS-specific data
    union {
        GLFWindow *windows;
        X11Window *x11;
    } win;
} Window;

Window *windowsWindowCreate(const WindowProperties props, Handle id) {
    Window *win = malloc(sizeof(Window));
    assert(win);
    win->type = WINDOWS;
    win->vsync = 1;
    win->id = id;
    win->win.windows = create_glf_window(props);
    return win;
}

bool window_display(Window *win) {
    // windows_window_display will look at the common fields and win.windows.
    // unix_window_display will look at the common fields and win.x11.
    return (WINDOWS == win->type) ? windows_window_display(win)
        : (X11 == win->type) ? unix_window_display(win)
        : 0;
}

Option 2: function pointers

typedef struct Window {
    //common data
    unsigned id;
    bool vsync;

    //Store the pointers to the OS-specific functions
    bool (*windows_display)(struct Window *win);

    //OS-specific data
    union {
        GLFWindow *windows;
        X11Window *x11;
    } win;
} Window;

Window *windowsWindowCreate(const WindowProperties props, Handle id) {
    Window *win = malloc(sizeof(Window));
    assert(win);
    win->vsync = 1;
    win->id = id;
    win->win.windows = create_glf_window(props);

    //Set the function pointers to the correct versions
    win->windows_display = windows_window_display;

    return win;
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论