如何在C++ SDL游戏的Game类不同方法中使用/修改其他类对象
SDL游戏开发中对象初始化与内存管理优化
问题概述
我用SDL开发C++游戏,主函数流程如下:
- 创建Game对象(初始化SDL窗口、相机等核心对象)
- 调用Game的
start()函数(创建Entity、TileMap、UI等组件) - 循环调用
gameLoop()(处理物理逻辑)和RenderLoop()(渲染),直到窗口关闭 - 调用
CleanUp()执行SDL_Quit()等清理操作
核心问题:Game类的多个方法需要访问TileMap、窗口等对象,但这些对象无法在构造函数的成员初始化列表中创建——部分对象依赖构造函数中后续计算得到的变量。比如创建SDL窗口需要先计算窗口尺寸、缩放因子,而RenderLoop又需要访问这个窗口。最初直接在构造函数内调用对象构造的写法报错,尝试成员初始化列表但因依赖关系不可行,目前用裸指针在堆上创建对象,在CleanUp中手动delete,希望换成更简洁、安全的实现方式。
初始代码示例
game.hpp
class Game { public: Game(); // 计划在此创建Window、Camera、Textures void start(); void gameLoop(const Uint8* p_keyBoardState); void RenderLoop(); void CleanUp(); const int reference_win_width = 1920; const int reference_win_height = 1080; int win_height; int win_width; /* Textures */ SDL_Texture* Dirt_Texture; SDL_Texture* Test_Texture; /* 渲染相关对象 */ Camera playerCamera; float scalefactor; RenderWindow window; TileMap TestMap; };
game.cpp(简化版)
Game::Game() { // 初始化必要对象 win_width = 2000; win_height = 1000; float widthScaleFactor = win_width / (float)reference_win_width; float heightScaleFactor = win_height / (float)reference_win_height; scalefactor = 1; window("TestGame", win_width, win_height, scalefactor); // 此处报错:无法直接调用构造函数初始化已声明的对象 // std::cout << window.getRefreshRate() << std::endl; Dirt_Texture = window.loadTexture("res/gfx/Dirt_Texture.png"); Test_Texture = window.loadTexture("res/gfx/Test.png"); playerCamera(Vector2f(0,0), Vector2f(100,100)); // 同样报错 } Game::RenderLoop() { // 渲染逻辑 window.display(); window.clear(); }
当前临时方案
在game.hpp中声明指针成员(如Camera* playerCamera;),在cpp中用new在堆上创建对象,最后在CleanUp()中手动delete。但这种方式需要手动管理内存,容易出现泄漏。
优化方案
方案1:使用智能指针自动管理内存
用std::unique_ptr替代裸指针,无需手动调用delete,智能指针会在对象生命周期结束时自动释放内存。
修改后的game.hpp
#include <memory> // 引入智能指针头文件 class Game { public: Game(); void start(); void gameLoop(const Uint8* p_keyBoardState); void RenderLoop(); void CleanUp(); // 此时无需手动delete智能指针管理的对象,仅需清理SDL纹理等资源 const int reference_win_width = 1920; const int reference_win_height = 1080; int win_height; int win_width; /* Textures */ SDL_Texture* Dirt_Texture; SDL_Texture* Test_Texture; /* 渲染相关对象 - 改用智能指针 */ std::unique_ptr<Camera> playerCamera; float scalefactor; std::unique_ptr<RenderWindow> window; std::unique_ptr<TileMap> TestMap; };
修改后的game.cpp构造函数
Game::Game() { win_width = 2000; win_height = 1000; float widthScaleFactor = win_width / (float)reference_win_width; float heightScaleFactor = win_height / (float)reference_win_height; scalefactor = 1; // 使用std::make_unique创建对象,自动管理内存 window = std::make_unique<RenderWindow>("TestGame", win_width, win_height, scalefactor); Dirt_Texture = window->loadTexture("res/gfx/Dirt_Texture.png"); Test_Texture = window->loadTexture("res/gfx/Test.png"); playerCamera = std::make_unique<Camera>(Vector2f(0,0), Vector2f(100,100)); } Game::RenderLoop() { // 访问时用->替代. window->display(); window->clear(); }
方案2:延迟初始化(给对象添加默认构造+初始化方法)
如果不想用指针,可以给RenderWindow、Camera等类添加默认构造函数,再提供一个init()或setup()方法,在Game构造函数完成变量计算后调用初始化方法。
示例:修改RenderWindow类
class RenderWindow { public: RenderWindow() = default; // 默认构造函数 void init(const std::string& title, int width, int height, float scale) { // 原来构造函数中的逻辑移到这里 window = SDL_CreateWindow(title.c_str(), ...); // 其他初始化操作 } // 其他成员函数... };
修改Game类的构造函数
Game::Game() { win_width = 2000; win_height = 1000; float widthScaleFactor = win_width / (float)reference_win_width; float heightScaleFactor = win_height / (float)reference_win_height; scalefactor = 1; // 调用初始化方法 window.init("TestGame", win_width, win_height, scalefactor); Dirt_Texture = window.loadTexture("res/gfx/Dirt_Texture.png"); Test_Texture = window.loadTexture("res/gfx/Test.png"); playerCamera.init(Vector2f(0,0), Vector2f(100,100)); }
这种方式保持成员为值类型,避免指针操作,同时解决了依赖后续变量初始化的问题。
方案3:重构为工厂方法模式
将Game对象的创建逻辑分离到静态工厂方法中,先完成所有变量计算,再通过初始化列表创建Game对象及内部成员。
修改后的Game类
class Game { public: // 私有构造函数,仅由工厂方法调用 Game(int winW, int winH, float scale) : win_width(winW), win_height(winH), scalefactor(scale), window("TestGame", winW, winH, scale), playerCamera(Vector2f(0,0), Vector2f(100,100)) { // 初始化纹理 Dirt_Texture = window.loadTexture("res/gfx/Dirt_Texture.png"); Test_Texture = window.loadTexture("res/gfx/Test.png"); } // 静态工厂方法,负责计算变量并创建Game对象 static std::unique_ptr<Game> create() { const int reference_win_width = 1920; const int reference_win_height = 1080; int win_width = 2000; int win_height = 1000; float widthScaleFactor = win_width / (float)reference_win_width; float heightScaleFactor = win_height / (float)reference_win_height; float scalefactor = 1; return std::make_unique<Game>(win_width, win_height, scalefactor); } // 其他成员函数... };
主函数中使用方式
int main() { auto game = Game::create(); game->start(); // 循环渲染逻辑... game->CleanUp(); return 0; }
这种方式完全利用成员初始化列表,避免了延迟初始化或指针,代码更符合C++初始化规范。
内容的提问来源于stack exchange,提问作者Blib
相关产品推荐
相关产品推荐

