(2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?

(2 questions) 'class' type redefinition (even with #pragma once), and static member object initialization inside a static function?

本文关键字:静态函数 静态 初始化 成员对象 即使 类型 问题 新定义 #pragma 定义 一次      更新时间:2023-10-16

我一直在做我的第一个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(中定义了对象,然后在代码文件(zahos.cpp(中重新定义了它,最后我使用复制运算符Model model(gVertexBufferData, gColorBufferData); mModel = model;在静态函数中创建了类。我对这种工作方式有很大的怀疑(因为复制操作符只做浅层复制(,而且我不知道如何使用指针在函数中定义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 corenlayout(location = 0) in vec3 vertexPosition_modelspace;nlayout(location = 1) in vec3 vertexColor;nout vec3 fragmentColor;nnuniform mat4 MVP;nnvoid main()n{ntgl_Position =  MVP * vec4(vertexPosition_modelspace, 1);ntntfragmentColor = vertexColor;n}nn#version 330 corenin vec3 fragmentColor;nout vec3 color;nnvoid main()n{ntcolor = 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: %sn", 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("%sn", &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("%sn", &fragmentShaderErrorMessage[0]);
}
// Link the program
printf("Linking programn");
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("%sn", &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 GLFWn");
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 windown");
glfwTerminate();
return GLFW_WINDOW_CREATION_FAIL;
}
glfwMakeContextCurrent(window);
// Initialize GLAD and OpenGL
int gladInitRes = gladLoadGL();
if (!gladInitRes) {
fprintf(stderr, "Unable to initialize gladn");
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);
}
};
}

main.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"answers"Mainframe"两次,一次在zachos.h中,一次是在zachos.cpp中。您应该用在标头中声明该类

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

然后用在cpp中定义类

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

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

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