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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:06:02