You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨窗口库返回通用窗口指针的C++图形引擎实现方案咨询

解决方案:摆脱void*,实现类型安全的通用窗口句柄返回

针对你遇到的void*强制转换冗余、create方法无法返回通用窗口指针的问题,结合SOLID原则,下面提供几个可行的实现方案:


方案1:用std::any替代void*实现类型安全的句柄存储

C++17引入的std::any可以安全存储任意类型的对象,避免裸void*的强制转换风险,同时保持接口的通用性。

修改IWindow接口

// IWindow.h
#include <any>

class IWindow
{
protected:
    std::any pWindow; // 替换void*
    bool isOpen;
public:
    IWindow() : isOpen(true) {}
    virtual void getEvent() = 0;
    // 修改create返回std::any,支持直接获取句柄
    virtual std::any create(int width, int height) = 0;
    virtual bool windowShouldClose() { return this->isOpen; };
    // 类型安全的原生句柄获取模板方法
    template<typename T>
    T* getNativeWindow() {
        return std::any_cast<T*>(pWindow);
    }
    virtual ~IWindow(){};
};

GLFWindow实现

// GLFWindow.cpp
#include "GLFWindow.h"
#include <GLFW/glfw3.h>

std::any GLFWindow::create(int width, int height)
{
    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan", nullptr, nullptr);
    pWindow = window; // 直接存储,无需强制转换
    return window;
}

void GLFWindow::getEvent()
{
    glfwPollEvents();
    // 类型安全获取句柄
    this->isOpen = !glfwWindowShouldClose(getNativeWindow<GLFWwindow>());
}

main中调用

// main.cpp
auto windowHandle = windowManager->create(config->window_w, config->window_h);
// 若需原生句柄(如与Vulkan交互),明确类型获取
if (auto glfwWindow = windowManager->getNativeWindow<GLFWwindow>()) {
    // 执行GLFW特定操作
}

方案2:封装原生句柄的抽象接口+工厂模式

如果不想依赖C++17特性,可以自定义NativeWindowHandle抽象类,派生类对应不同库的句柄,通过工厂根据YAML配置创建实例,让create返回这个抽象句柄。

定义NativeWindowHandle接口

// NativeWindowHandle.h
class NativeWindowHandle {
public:
    virtual ~NativeWindowHandle() = default;
};

// GLFW专属句柄实现
class GLFWWindowHandle : public NativeWindowHandle {
private:
    GLFWwindow* handle;
public:
    GLFWWindowHandle(GLFWwindow* h) : handle(h) {}
    GLFWwindow* get() const { return handle; }
};

// SDL、SFML的句柄实现逻辑类似

修改IWindow接口

// IWindow.h
#include "NativeWindowHandle.h"
#include <memory>

class IWindow
{
protected:
    std::unique_ptr<NativeWindowHandle> pWindow;
    bool isOpen;
public:
    IWindow() : isOpen(true) {}
    virtual std::unique_ptr<NativeWindowHandle> create(int width, int height) = 0;
    virtual void getEvent() = 0;
    virtual bool windowShouldClose() { return this->isOpen; };
    // 类型安全获取具体句柄
    template<typename T>
    T* getNativeHandle() {
        return dynamic_cast<T*>(pWindow.get())->get();
    }
    virtual ~IWindow(){};
};

GLFWindow的create实现

std::unique_ptr<NativeWindowHandle> GLFWindow::create(int width, int height)
{
    glfwInit();
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
    GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan", nullptr, nullptr);
    pWindow = std::make_unique<GLFWWindowHandle>(window);
    return std::move(pWindow);
}

方案3:改进PIMPL模式,隐藏实现同时暴露原生句柄

把具体窗口库的实现完全隐藏在PIMPL中,IWindow只对外暴露通用接口,同时通过模板方法安全获取原生句柄。

IWindow的PIMPL结构

// IWindow.h
#include <memory>

class IWindowImpl; // 前向声明

class IWindow
{
protected:
    std::unique_ptr<IWindowImpl> pImpl;
    bool isOpen;
public:
    IWindow();
    virtual std::any create(int width, int height) = 0;
    virtual void getEvent() = 0;
    virtual bool windowShouldClose() { return this->isOpen; };
    // 模板方法获取原生句柄
    template<typename T>
    T* getNativeWindow() {
        return pImpl->getNativeWindow<T>();
    }
    virtual ~IWindow(){};
};

// 具体实现的基类
class IWindowImpl {
public:
    virtual ~IWindowImpl() = default;
    virtual void getEvent() = 0;
    template<typename T>
    T* getNativeWindow() {
        return static_cast<T*>(getNativeWindowPtr());
    }
protected:
    virtual void* getNativeWindowPtr() = 0;
};

GLFW的Impl实现

// GLFWindow.cpp
#include "GLFWindow.h"
#include <GLFW/glfw3.h>

class GLFWWindowImpl : public IWindowImpl {
private:
    GLFWwindow* window;
public:
    GLFWWindowImpl(int width, int height) {
        glfwInit();
        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
        window = glfwCreateWindow(width, height, "Vulkan", nullptr, nullptr);
    }
    void getEvent() override {
        glfwPollEvents();
    }
protected:
    void* getNativeWindowPtr() override {
        return window;
    }
};

std::any GLFWindow::create(int width, int height)
{
    pImpl = std::make_unique<GLFWWindowImpl>(width, height);
    return pImpl->getNativeWindow<GLFWwindow>();
}

void GLFWindow::getEvent()
{
    pImpl->getEvent();
    this->isOpen = !glfwWindowShouldClose(pImpl->getNativeWindow<GLFWwindow>());
}

关键注意事项

  • 所有方案均遵循依赖倒置原则:高层模块(main)仅依赖IWindow抽象,不耦合具体库实现
  • 彻底避免裸void*的强制转换,通过类型安全的方式获取原生句柄
  • 可结合工厂模式:根据YAML配置字符串,创建对应GLFWindow/SDLWindow/SFMLWindow实例,返回IWindow指针

内容的提问来源于stack exchange,提问作者Coriolis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 09:45:50