c++ - (2 个问题) 'class' 类型重定义(即使使用#pragma once),以及静态函数内部的静态成员对象初始化?

标签 c++ class glfw

我一直在研究我的第一个 opengl、glfw 和 glm 项目(在 cmake 中),同时遵循在线教程,我想开始将我的代码组织到特定的类中以执行特定的任务(例如用于组织着色器的模型类和顶点);然而,一旦我组织了我的代码,我就遇到了两个问题。

首先,在我终于摆脱了代码中的所有语法错误之后,我遇到了两个单独的类(一个是静态类)的编译错误 'class' type redefinition 两次。我在唯一的头文件 (zachos.h) 的最顶部有 #pragma once,所以我不知道这里的问题是什么。为什么我的代码(见下文)会抛出这个错误?列出的确切错误消息是:

zachos.cpp(94): error C2011: 'zachos::Model': 'class' type redefinition
zachos.h(53): note: see declaration of 'zachos::Model'
zachos.cpp(173): error C2011: 'zachos::Mainframe': 'class' type redefinition
zachos.h(84): note: see declaration of 'zachos::Mainframe'

其次,我需要从该类的静态函数内部初始化一个静态成员对象。我使用 static Model mModel; 在我的头文件 (zachos.h) 中定义了对象,然后在我的代码文件 (zachos.cpp) 中重新定义了它,最后我在静态函数中创建了类使用复制操作符 Model model(gVertexBufferData, gColorBufferData); mModel = 模型;。我对这个工作有严重的怀疑(因为复制运算符只做浅拷贝),我不知道如何使用指针在函数内定义 mModel(我相信我必须使用 delete以某种方式)。这种形式的对象初始化是否有问题,有没有更好的方法?

代码(所有文件都在同一个目录下并被CMake引用,如果需要我也可以提供CMakeLists.txt文件):

zachos.h:

#pragma once

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <stdio.h>
#include <string.h>

#include <vector>

#include <sstream>
#include <iostream>
#include <fstream>

#include <cstdlib>
#include <ctime>

/*
Namespace that contains all basic codestuff for zachos.
*/
namespace zachos {
    // Constant data

    static const std::string DATA_DEF("#version 330 core\nlayout(location = 0) in vec3 vertexPosition_modelspace;\nlayout(location = 1) in vec3 vertexColor;\nout vec3 fragmentColor;\n\nuniform mat4 MVP;\n\nvoid main()\n{\n\tgl_Position =  MVP * vec4(vertexPosition_modelspace, 1);\n\t\n\tfragmentColor = vertexColor;\n}\n\n#version 330 core\nin vec3 fragmentColor;\nout vec3 color;\n\nvoid main()\n{\n\tcolor = fragmentColor;\n}");
    std::vector<GLfloat> gVertexBufferData = {
                -1.0f, -1.0f, -1.0f, // triangle 1 : begin
                -1.0f, -1.0f, 1.0f,
                -1.0f, 1.0f, 1.0f, // triangle 1 : end
                1.0f, 1.0f, -1.0f, // triangle 2 : begin
                -1.0f, -1.0f, -1.0f,
                -1.0f, 1.0f, -1.0f, // triangle 2 : end
                1.0f, -1.0f, 1.0f,
                -1.0f, -1.0f, -1.0f,
                1.0f, -1.0f, -1.0f,
                1.0f, 1.0f, -1.0f,
                1.0f, -1.0f, -1.0f,
                -1.0f, -1.0f, -1.0f,
                -1.0f, -1.0f, -1.0f,
                -1.0f, 1.0f, 1.0f,
                -1.0f, 1.0f, -1.0f,
                1.0f, -1.0f, 1.0f,
                -1.0f, -1.0f, 1.0f,
                -1.0f, -1.0f, -1.0f,
                -1.0f, 1.0f, 1.0f,
                -1.0f, -1.0f, 1.0f,
                1.0f, -1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                1.0f, -1.0f, -1.0f,
                1.0f, 1.0f, -1.0f,
                1.0f, -1.0f, -1.0f,
                1.0f, 1.0f, 1.0f,
                1.0f, -1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                1.0f, 1.0f, -1.0f,
                -1.0f, 1.0f, -1.0f,
                1.0f, 1.0f, 1.0f,
                -1.0f, 1.0f, -1.0f,
                -1.0f, 1.0f, 1.0f,
                1.0f, 1.0f, 1.0f,
                -1.0f, 1.0f, 1.0f,
                1.0f, -1.0f, 1.0f
    };
    std::vector<GLfloat> gColorBufferData(12 * 3 * 3, 0);

    /*
    Enum of all possible error codes for the program to return on its own
    */
    enum ErrorCodes {
        SUCCESS,
        GLFW_INIT_FAIL,
        GLFW_WINDOW_CREATION_FAIL,
        GLAD_INIT_FAIL,
        WINDOW_FAIL
    };

    /*
    Error callback function for glfw. Nothing special.
    */
    void errorCallback(int error, const char* description);

    /*
    Load shaders function for convenience. Used especially by the Model class.
    */
    GLuint loadShaders(std::string shaders);

    /*
    Class for creating models; it holds a VBO, CBO, and programID.
    */
    class Model {
    public:
        std::vector<GLfloat> mVertexBufferData;
        std::vector<GLfloat> mColorBufferData;

        GLuint VBO;
        GLuint CBO;

        GLuint programID;

        glm::mat4 model;

        /*
        Default Constructor. Must contain all vertex and color data from the get go.
        */
        Model(std::vector<GLfloat> vertexBufferData, std::vector<GLfloat> colorBufferData);

        /*
        Model update() function, called every "tick"
        */
        virtual void update();

        /*
        Model draw() function, called to draw the model
        */
        virtual void draw();
    };

    /*
    Wrapper class of the main window for handling events and perspective.
    */
    class Mainframe {
    public:
        static GLFWwindow* window;

        static glm::mat4 projection;
        static glm::mat4 view;

        static Model mModel;

        static int i;

        // Event functions

        static void framebufferSizeCallback(GLFWwindow* window, int width, int height);
        static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);

        /*
        Class initialization function.
        */
        static int init();

        /*
        Frame by frame drawing function.
        */
        static int draw();

        /*
        Get whether the window should close or not
        */
        static bool shouldClose();
    };
}

zachos.cpp:

#include "zachos.h"

namespace zachos {

    void errorCallback(int error, const char* description) {
        fprintf(stderr, "GLFW error %d: %s\n", error, description);
    }

    GLuint loadShaders(std::string shaders) {

        // Create the shaders
        GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
        GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

        // Read the shader code
        std::string shaderCode;
        std::string vertexShaderCode;
        std::string fragmentShaderCode;

        //std::ifstream shaderStream(file_path, std::ios::in);
        if (/*shaderStream.is_open()*/ true) {
            //std::stringstream sstr;
            //sstr << shaderStream.rdbuf();
            //shaderCode = sstr.str();
            shaderCode = shaders;
            //shaderStream.close();

            size_t val = shaderCode.find("#version", 8);
            vertexShaderCode = shaderCode.substr(0, val);
            fragmentShaderCode = shaderCode.substr(val);
        }
        else {
            //printf("Impossible to open \"%s\". Are you in the right directory? Don't forget to read the FAQ!\n", file_path);
            getchar();
            return 0;
        }

        GLint result = GL_FALSE;
        int infoLogLength;

        // Compile Vertex Shader
        char const * vertexSourcePointer = vertexShaderCode.c_str();
        glShaderSource(vertexShaderID, 1, &vertexSourcePointer, nullptr);
        glCompileShader(vertexShaderID);

        // Check Vertex Shader
        glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result);
        glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
        if (infoLogLength > 0) {
            std::vector<char> vertexShaderErrorMessage(infoLogLength + 1);
            glGetShaderInfoLog(vertexShaderID, infoLogLength, nullptr, &vertexShaderErrorMessage[0]);
            printf("%s\n", &vertexShaderErrorMessage[0]);
        }

        // Compile Fragment Shader
        char const * fragmentSourcePointer = fragmentShaderCode.c_str();
        glShaderSource(fragmentShaderID, 1, &fragmentSourcePointer, nullptr);
        glCompileShader(fragmentShaderID);

        // Check Fragment Shader
        glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result);
        glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
        if (infoLogLength > 0) {
            std::vector<char> fragmentShaderErrorMessage(infoLogLength + 1);
            glGetShaderInfoLog(fragmentShaderID, infoLogLength, nullptr, &fragmentShaderErrorMessage[0]);
            printf("%s\n", &fragmentShaderErrorMessage[0]);
        }

        // Link the program
        printf("Linking program\n");
        GLuint programID = glCreateProgram();
        glAttachShader(programID, vertexShaderID);
        glAttachShader(programID, fragmentShaderID);
        glLinkProgram(programID);

        // Check the program
        glGetProgramiv(programID, GL_LINK_STATUS, &result);
        glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
        if (infoLogLength > 0) {
            std::vector<char> programErrorMessage(infoLogLength + 1);
            glGetProgramInfoLog(programID, infoLogLength, nullptr, &programErrorMessage[0]);
            printf("%s\n", &programErrorMessage[0]);
        }

        glDetachShader(programID, vertexShaderID);
        glDetachShader(programID, fragmentShaderID);

        glDeleteShader(vertexShaderID);
        glDeleteShader(fragmentShaderID);

        return programID;
    }

    class Model {
    public:

        std::vector<GLfloat> mVertexBufferData;
        std::vector<GLfloat> mColorBufferData;

        GLuint VBO;
        GLuint CBO;

        GLuint programID;

        glm::mat4 model = glm::mat4(1.0f);

        Model(std::vector<GLfloat> vertexBufferData, std::vector<GLfloat> colorBufferData) {

            mVertexBufferData = vertexBufferData;
            mColorBufferData = colorBufferData;

            // Generate 1 buffer, put the resulting identifier in vertexbuffer
            glGenBuffers(1, &VBO);
            // The following commands will talk about our 'vertexbuffer' buffer
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            // Give our vertices to OpenGL.
            glBufferData(GL_ARRAY_BUFFER, sizeof(mVertexBufferData), &mVertexBufferData.front(), GL_STATIC_DRAW);

            glGenBuffers(1, &CBO);
            glBindBuffer(GL_ARRAY_BUFFER, CBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(mColorBufferData), &mColorBufferData.front(), GL_STATIC_DRAW);

            // Create and compile our GLSL program from the shaders
            GLuint programID = loadShaders(zachos::DATA_DEF);
            glUseProgram(programID);
        }

        virtual void update() {
            for (int v = 0; v < 12 * 3; v++) {
                mColorBufferData[3 * v + 0] = (float)std::rand() / RAND_MAX;
                mColorBufferData[3 * v + 1] = (float)std::rand() / RAND_MAX;
                mColorBufferData[3 * v + 2] = (float)std::rand() / RAND_MAX;
            }
            glBufferData(GL_ARRAY_BUFFER, sizeof(mColorBufferData), &mColorBufferData.front(), GL_STATIC_DRAW);
        }

        virtual void draw() {
            glEnableVertexAttribArray(0);
            glBindBuffer(GL_ARRAY_BUFFER, VBO);
            glVertexAttribPointer(
                0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
                3,                  // size
                GL_FLOAT,           // type
                GL_FALSE,           // normalized?
                0,                  // stride
                (void*)0            // array buffer offset
            );
            glEnableVertexAttribArray(1);
            glBindBuffer(GL_ARRAY_BUFFER, CBO);
            glVertexAttribPointer(
                1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
                3,                                // size
                GL_FLOAT,                         // type
                GL_FALSE,                         // normalized?
                0,                                // stride
                (void*)0                          // array buffer offset
            );

            // Setup some 3D stuff
            glm::mat4 mvp = Mainframe::projection * Mainframe::view * model;

            GLuint MatrixID = glGetUniformLocation(programID, "MVP");
            glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &mvp[0][0]);

            // Draw the array
            glDrawArrays(GL_TRIANGLES, 0, mVertexBufferData.size() / 3);

            glDisableVertexAttribArray(0);
            glDisableVertexAttribArray(1);
        }
    };

    class Mainframe {
    public:
        static GLFWwindow* window;

        static glm::mat4 projection;
        static glm::mat4 view;

        static Model mModel;

        static int i;

        static void framebufferSizeCallback(GLFWwindow* window, int width, int height) {
            glViewport(0, 0, width, height);
            glm::perspective(glm::radians(45.0f), (float)width / (float)height, 0.1f, 100.0f);
        }

        static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
            switch (key) {
            case GLFW_KEY_ESCAPE:

                break;
            }
        }

        static int init() {
            // Initialize GLFW
            int glfwInitRes = glfwInit();
            if (!glfwInitRes) {
                fprintf(stderr, "Unable to initialize GLFW\n");
                return GLFW_INIT_FAIL;
            }

            // Set GLFW flags. Not exactly sure if these are needed.
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
            glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

            // Attempt to create the main window.
            window = glfwCreateWindow(1280, 720, "InitGL", nullptr, nullptr);
            if (!window) {
                fprintf(stderr, "Unable to create GLFW window\n");
                glfwTerminate();
                return GLFW_WINDOW_CREATION_FAIL;
            }
            glfwMakeContextCurrent(window);

            // Initialize GLAD and OpenGL
            int gladInitRes = gladLoadGL();
            if (!gladInitRes) {
                fprintf(stderr, "Unable to initialize glad\n");
                glfwTerminate();
                return GLAD_INIT_FAIL;
            }

            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

            glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
            glfwSetKeyCallback(window, keyCallback);

            // Create da CUBANGLÉ
            GLuint VertexArrayID;
            glGenVertexArrays(1, &VertexArrayID);
            glBindVertexArray(VertexArrayID);

            for (int v = 0; v < 12 * 3; v++) {
                gColorBufferData[3 * v + 0] = (float)std::rand() / RAND_MAX;
                gColorBufferData[3 * v + 1] = (float)std::rand() / RAND_MAX;
                gColorBufferData[3 * v + 2] = (float)std::rand() / RAND_MAX;
            }
            Model model(gVertexBufferData, gColorBufferData);
            mModel = model;

            // Set the clear color
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

            projection = glm::perspective(glm::radians(45.0f), (float)1280 / (float)720, 0.1f, 100.0f);

            view = glm::lookAt(
                glm::vec3(4, 3, 3), // Camera is at (4,3,3), in World Space
                glm::vec3(0, 0, 0), // and looks at the origin
                glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
            );

            i = 60;

            return SUCCESS;
        }

        static int draw() {

            if (i <= 0) {
                view = glm::lookAt(
                    glm::vec3(3 + 2 * (float)std::rand() / RAND_MAX, 3 + 2 * (float)std::rand() / RAND_MAX, 3 + 2 * (float)std::rand() / RAND_MAX), // Camera is at (), in World Space
                    glm::vec3(0, 0, 0), // and looks at the origin
                    glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
                );
                mModel.update();

                i = 60;
            }
            i--;

            mModel.draw();

            glfwSwapBuffers(window);
        }

        static bool shouldClose() {
            return glfwWindowShouldClose(window);
        }
    };

}

主要.cpp:

#include "zachos.h"

/*
I'm pretty sure you know what this function is.
*/
int main(int argc, char* argv[]) {
    // Seed the random number generator
    std::srand(static_cast<unsigned int>(std::time(nullptr)));

    // Implement Mainframe for shorthand
    using zachos::Mainframe;
    // set GLFW error callback function
    glfwSetErrorCallback(zachos::errorCallback);

    // Run the window initiazation function
    int value = Mainframe::init();
    if (!value) {
        // Return if failed
        return value;
    }

    // Main loop
    while (!Mainframe::shouldClose()) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LESS);

        glfwPollEvents();

        // Actually does the hard work
        Mainframe::draw();
    }

    glfwTerminate();

    return zachos::SUCCESS;
}

我还知道此代码中存在的其他可能问题。如果愿意,您也可以提及它们,但我的主要问题围绕这两个主要问题展开。

最佳答案

您似乎两次声明类“Model”和“Mainframe”,一次在 zachos.h 中,一次在 zachos.cpp 中。您应该在 header 中声明类

class Model {
public:
   virtual void update();
   ...
}

然后在cpp中定义类

void Model::update() {
   ...
}

header 告诉编译器类的结构和内容,cpp 提供函数的实际作用。

关于你的第二点,我不确定你正在尝试实现什么,所以不知道是否有更好的方法。

关于c++ - (2 个问题) 'class' 类型重定义(即使使用#pragma once),以及静态函数内部的静态成员对象初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58715694/

相关文章:

c++ - 这会泄漏内存吗?

jQuery:检查 div 的 CSS 是否:left == 0

python - 派生 Enum 时使用 __class__ 获取属性

opengl - 未定义的 glew 引用

linux - 在 Linux 上静态构建 glew 和 glfw

c++ - 传递给着色器的颜色不起作用

c++ - 带有 lambda 的 noexcept 运算符。 MSVC 错误?

c++ - 我用 C++ 编写的文件中有更多字符

c++ - 静态库链接失败,共享库链接成功

PHP:mysql 语句有问题。