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

typedef struct {WindowData data;bool vsync;} Window;typedef struct{Window window;GLFWwindow *native_

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744272375a4566164.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信