为什么我的 C++ 程序在使用构造函数时会崩溃?
Why does my C++ program crash when using a constructor?
我正在按照 "learnopengl.com" 教程制作一个简单的 OpenGL 程序。现在代码应该只显示一个橙色三角形。
我的代码:
ScreenManager.h
#ifndef SCREEN_MANAGER_H
#define SCREEN_MANAGER_H
#define GLEW_STATIC
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
#include "Input.h"
#include "Renderer.h"
class ScreenManager
{
public:
ScreenManager(void);
bool isCloseRequested();
void render();
void update();
void dispose();
private:
GLFWwindow* window;
Renderer renderer;
};
#endif
ScreenManager.cpp
#include "ScreenManager.h"
ScreenManager::ScreenManager(void)
{
// Initialize GLFW library
glfwInit();
// Specify the opengl version to 3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Specify opengl profile to core profile
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Disable resizing
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create the window object
window = glfwCreateWindow(800, 600, "test", nullptr, nullptr);
// Make the GL context the active context in the thread
glfwMakeContextCurrent(window);
// Error check
if(window==NULL){
std::cout << "failed to create GLFW window :( " << std::endl;
dispose();
}
// Make sure that GLEW use modern techniques to manage opengl functionality
glewExperimental = GL_TRUE;
// Initialize GLEW and check for errors
if(glewInit() != GLEW_OK){
std::cout << "failed to initialize glew :( " << std::endl;
}
// Specify opengl viewport => bottom left coordinates and window size
glViewport(0, 0, 800, 600);
// Register the events for GLFW => currently :keyboard
Input input(window);
renderer.init();
}
// Check if window is closed
bool ScreenManager::isCloseRequested(){
if(glfwWindowShouldClose(window))
return true;
return false;
}
// Clear screen and swap buffers
void ScreenManager::render(){
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
renderer.render();
glfwSwapBuffers(window);
}
// Check for events (registered events)
void ScreenManager::update(){
glfwPollEvents();
}
void ScreenManager::dispose(){
glfwTerminate();
}
Renderer.h
#ifndef RENDERER_H
#define RENDERER_H
#define GLEW_STATIC
#include <GL\glew.h>
#include <iostream>
class Renderer
{
public:
Renderer(void);
void init();
void render();
private:
void testShape();
GLuint createVertexShader(GLuint &shader);
GLuint createFragmentShader(GLuint &shader);
void createShaderProgram(GLuint &program);
};
#endif
Renderer.cpp
#include "Renderer.h"
GLuint program;
GLuint vertexShader;
GLuint fragmentShader;
GLuint VAO;
Renderer::Renderer(){
//init();
}
void Renderer::init(){
testShape();
createShaderProgram(program);
}
void Renderer::render(){
glUseProgram(program);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
void Renderer::testShape(){
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint VBO;
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3* sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(VBO, 0);
glBindVertexArray(0);
}
GLuint Renderer::createVertexShader(GLuint &shader){
const GLchar* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main(){\n"
" gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}";
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLint success;
GLchar info[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(vertexShader, 512, NULL, info);
std::cout << "couldn't compile shader :(/n" << info << std::endl;
}
return vertexShader;
}
GLuint Renderer::createFragmentShader(GLuint &shader){
const GLchar* fragmentShaderSource =
"#version 330 core\n"
"out vec4 color;\n"
"void main(){\n"
" color = vec4(1.0, 0.5, 0.2, 0);\n"
"}";
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLint success;
GLchar info[512];
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(fragmentShader, 512, NULL, info);
std::cout << "couldn't compile shader :(\n" << info << "\n" << std::endl;
}
return fragmentShader;
}
void Renderer::createShaderProgram(GLuint &program){
program = glCreateProgram();
glAttachShader(program, createVertexShader(vertexShader));
glAttachShader(program, createFragmentShader(fragmentShader));
glLinkProgram(program);
GLint success;
GLchar info[512];
glGetProgramiv(program, GL_LINK_STATUS, &success);
if(!success){
glGetProgramInfoLog(program, 512, NULL, info);
std::cout << "couldn't link program :(\n" << info << "\n" << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
好吧,如果我不使用 Renderer class 构造函数而只使用 init() 函数,如果我改用构造函数(在取消注释 init() 并注释 renderer.init()) 程序崩溃。
main 函数在一个单独的 class 中,它所做的只是循环调用 ScreenManager 渲染函数。
当您在构造函数中调用 init
时,它会在 ScreenManager
的成员构造期间调用,这发生在 ScreenManager
的构造函数主体执行之前。
此时,OpenGL 尚未初始化,这就是您崩溃的原因。
我正在按照 "learnopengl.com" 教程制作一个简单的 OpenGL 程序。现在代码应该只显示一个橙色三角形。
我的代码:
ScreenManager.h
#ifndef SCREEN_MANAGER_H
#define SCREEN_MANAGER_H
#define GLEW_STATIC
#include <GL\glew.h>
#include <GLFW\glfw3.h>
#include <iostream>
#include "Input.h"
#include "Renderer.h"
class ScreenManager
{
public:
ScreenManager(void);
bool isCloseRequested();
void render();
void update();
void dispose();
private:
GLFWwindow* window;
Renderer renderer;
};
#endif
ScreenManager.cpp
#include "ScreenManager.h"
ScreenManager::ScreenManager(void)
{
// Initialize GLFW library
glfwInit();
// Specify the opengl version to 3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// Specify opengl profile to core profile
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Disable resizing
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
// Create the window object
window = glfwCreateWindow(800, 600, "test", nullptr, nullptr);
// Make the GL context the active context in the thread
glfwMakeContextCurrent(window);
// Error check
if(window==NULL){
std::cout << "failed to create GLFW window :( " << std::endl;
dispose();
}
// Make sure that GLEW use modern techniques to manage opengl functionality
glewExperimental = GL_TRUE;
// Initialize GLEW and check for errors
if(glewInit() != GLEW_OK){
std::cout << "failed to initialize glew :( " << std::endl;
}
// Specify opengl viewport => bottom left coordinates and window size
glViewport(0, 0, 800, 600);
// Register the events for GLFW => currently :keyboard
Input input(window);
renderer.init();
}
// Check if window is closed
bool ScreenManager::isCloseRequested(){
if(glfwWindowShouldClose(window))
return true;
return false;
}
// Clear screen and swap buffers
void ScreenManager::render(){
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
renderer.render();
glfwSwapBuffers(window);
}
// Check for events (registered events)
void ScreenManager::update(){
glfwPollEvents();
}
void ScreenManager::dispose(){
glfwTerminate();
}
Renderer.h
#ifndef RENDERER_H
#define RENDERER_H
#define GLEW_STATIC
#include <GL\glew.h>
#include <iostream>
class Renderer
{
public:
Renderer(void);
void init();
void render();
private:
void testShape();
GLuint createVertexShader(GLuint &shader);
GLuint createFragmentShader(GLuint &shader);
void createShaderProgram(GLuint &program);
};
#endif
Renderer.cpp
#include "Renderer.h"
GLuint program;
GLuint vertexShader;
GLuint fragmentShader;
GLuint VAO;
Renderer::Renderer(){
//init();
}
void Renderer::init(){
testShape();
createShaderProgram(program);
}
void Renderer::render(){
glUseProgram(program);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
}
void Renderer::testShape(){
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint VBO;
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3* sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(VBO, 0);
glBindVertexArray(0);
}
GLuint Renderer::createVertexShader(GLuint &shader){
const GLchar* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 position;\n"
"void main(){\n"
" gl_Position = vec4(position.x, position.y, position.z, 1.0);\n"
"}";
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
GLint success;
GLchar info[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(vertexShader, 512, NULL, info);
std::cout << "couldn't compile shader :(/n" << info << std::endl;
}
return vertexShader;
}
GLuint Renderer::createFragmentShader(GLuint &shader){
const GLchar* fragmentShaderSource =
"#version 330 core\n"
"out vec4 color;\n"
"void main(){\n"
" color = vec4(1.0, 0.5, 0.2, 0);\n"
"}";
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
GLint success;
GLchar info[512];
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success){
glGetShaderInfoLog(fragmentShader, 512, NULL, info);
std::cout << "couldn't compile shader :(\n" << info << "\n" << std::endl;
}
return fragmentShader;
}
void Renderer::createShaderProgram(GLuint &program){
program = glCreateProgram();
glAttachShader(program, createVertexShader(vertexShader));
glAttachShader(program, createFragmentShader(fragmentShader));
glLinkProgram(program);
GLint success;
GLchar info[512];
glGetProgramiv(program, GL_LINK_STATUS, &success);
if(!success){
glGetProgramInfoLog(program, 512, NULL, info);
std::cout << "couldn't link program :(\n" << info << "\n" << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
}
好吧,如果我不使用 Renderer class 构造函数而只使用 init() 函数,如果我改用构造函数(在取消注释 init() 并注释 renderer.init()) 程序崩溃。
main 函数在一个单独的 class 中,它所做的只是循环调用 ScreenManager 渲染函数。
当您在构造函数中调用 init
时,它会在 ScreenManager
的成员构造期间调用,这发生在 ScreenManager
的构造函数主体执行之前。
此时,OpenGL 尚未初始化,这就是您崩溃的原因。