跨窗口库返回通用窗口指针的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
相关产品推荐
相关产品推荐

