繁体   English   中英

有没有办法阻止 class 的默认构造函数为成员变量的单个实例运行?

[英]Is there a way to prevent the default constructor of a class from running for a single instance of a member variable?

对于我的游戏,假设我有一个名为 GameTexture 的 class,其中的默认构造函数如下所示:

GameTexture::GameTexture() {
    this->shader = ShaderManager::get_instance()->get_shader("2d_texture", "2d_texture", "", 0);
}

get_shader() 看起来像这样:

Shader* ShaderManager::get_shader(std::string vertex, std::string fragment, std::string geometry, unsigned int features) {
    if (!shader_map.contains(vertex)
    || !shader_map[vertex].contains(fragment)
    || !shader_map[vertex][fragment].contains(geometry)
    || !shader_map[vertex][fragment][geometry].contains(features)) {
        shader_map[vertex][fragment][geometry][features].init(vertex, fragment, geometry, features);
    }
    return &shader_map[vertex][fragment][geometry][features];
}

初始化着色器是这样开始的:

void Shader::init(std::string vertex_dir, std::string fragment_dir, std::string geometry_dir, unsigned int features) {
    ShaderManager* shader_manager = ShaderManager::get_instance();
    id = glCreateProgram();

请注意,默认将着色器设置为 nullptr 是不安全的,因为如果我们尝试渲染未加载的 GameTexture,程序将在尝试取消引用 nullptr 时立即崩溃。 因此,我们将其设置为默认着色器,即使有关纹理的其他所有内容都是默认值,也不会造成任何损坏。 就其本身而言,这很好,但如果我们在 OpenGL 初始化之前加载 GameTexture,就会出现问题。 假设我们再添加一个 singleton 叫做 RenderManager。 RenderManager负责创建一个window,加载OpenGL等。假设它是这样的:

class RenderManager {
public:
    RenderManager(RenderManager& other) = delete;
    void operator=(const RenderManager& other) = delete;

    SDL_Window* window;
    SDL_Renderer* sdl_renderer;
    SDL_GLContext sdl_context;
    int s_window_width;
    int s_window_height;

    GameTexture example_texture;

    static RenderManager* get_instance();
    void destroy_instance();
private:
    RenderManager();
    static RenderManager* instance;
};

RenderManager::RenderManager() {
    float width = 1920.0;
    float height = 1080.0;
    window = SDL_CreateWindow("Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_FULLSCREEN_DESKTOP);
    SDL_GetWindowSize(window, &s_window_width, &s_window_height);
    sdl_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED);
    sdl_context = SDL_GL_CreateContext(window);
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        std::cout << "Failed to initialize GLEW!" << std::endl;
    }
    SDL_GL_MakeCurrent(window, sdl_context);
    SDL_GL_SetSwapInterval(1);

    example_texture.init("example/path/here.png");
}

假设我们开始创建 RenderManager 的实例。 在调用构造函数之前,它会遍历其所有成员并找到 example_texture。 它调用 example_texture 的构造函数,告诉它获取着色器。 ShaderManager 尚未加载该着色器,因此它开始加载。 但是,这会导致程序崩溃,因为它正在调用 glCreateProgram(),尽管 OpenGL 尚未加载。

这引出了我的问题。 我知道我将手动初始化 GameTexture 的这个特定实例,事实上在这种情况下我需要查看尝试自行创建 GameTexture 的程序如何不起作用,所以有没有强制构造函数不为 GameTexture 的这个特定实例运行而不完全删除它的可能方法? 这样它可以作为成员变量存储在 RenderManager 中,但它不会在加载 gl 之前尝试调用任何 gl 函数。

请注意,我知道还有其他我愿意做的解决方案。 如果我要堆分配这个 GameTexture,它的构造函数将不会运行,直到我实际分配它。 这是我目前正在采用的方法,但我对堆分配的想法不满意,只是为了在所有上下文中将其用作堆栈分配的变量,而堆上没有其他 GameTexture 开始。

拥有构造函数的全部意义在于您必须运行一个。 如果不想运行一个构造函数,则必须运行另一个构造函数。 如果您没有不同的构造函数,则必须添加一个。 或者,将您不想在构造函数中运行的代码移到构造函数中,使其不在构造函数中,而是在其他地方。

坚持认为您必须拥有以某种方式行事的课程,这似乎将自己逼到了一个角落。 您希望每个着色器 object 实际上是一个着色器(不为空); 你想在每个纹理中获得一个着色器 object; 你想在 OpenGL 初始化之前创建一个纹理 object; 在 OpenGL 初始化之前,您无法获得着色器。 满足所有这些要求是不可能的。 你必须换一个。

一种可能性是您更改所有纹理必须具有着色器 object 的要求。我会考虑在 null state 中创建纹理 object,然后稍后将实际纹理加载到其中(正如您似乎已经在做的那样)并加载同时着色器。 我以前做过这个。 制作所有存在的texture对象的链接列表并不太难,然后在加载 OpenGL 时,你 go 通过它们并实际加载纹理。

另一个建议是在 OpenGL 初始化之前不要创建纹理 object。 初始化OpenGL,然后创建所有的贴图。 如果这意味着你的 window 和你的游戏渲染必须在两个不同的类中,那就这样吧。 如果你制作一个Window class 并放入一个Window window; 内部class RenderManager - 在GameTexture example_texture; - Window 的构造函数将在Window的构造函数之前GameTexture 然后,当您 go 创建纹理和着色器时,您将初始化 OpenGL 。


附加功能:

事实上,您不知道何时创建 window 有点奇怪。 通常您想知道您的代码以何种顺序运行,对吗? 创建window,然后初始化OpenGL,然后加载关卡文件,然后加载关卡的所有纹理,然后发送消息“有新玩家加入游戏”。 - 试图让这一切以正确的顺序发生而不实际说出顺序有时会导致灾难。 您可能已经感染了“单身狂”,并试图做一些花哨的 class 恶作剧,而不仅仅是。 告诉。 这。 电脑。 什么。 你。 想。 它。 到。 没关系,每个人都会经历那个阶段。

我注意到的另一件事是纹理通常不与着色器相关联。 通常,材质与着色器相关联——材质是着色器及其所需的所有纹理。 一些着色器使用零纹理(如扭曲效果); 有些使用多个(如漫反射颜色纹理和法线贴图)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2023 STACKOOM.COM