Window class for a game engine
Window::Init() performs OpenGL initialization and creates the GL window, I do not completely agree with this: I'd avoid to perform expensive tasks inside ctor (which should, IMO, just initialize the object in a consistent state). Initialization may be done lazily when required (better, I think) or made explicit with a public Initialize() method (which has the disadvantage to be another function to call and the overhead of the checks to determine if it has been called or not but where you can use virtual functions without worries).

Your actual Window::Init() returns a bool which is simply unused. However when initialization fails the object is not in a valid state and any other function call may simply crash. Calling code has to any clue and it can't gracefully exit. Feel free to throw an exception (even easier if you have a separate Initialize() method) instead of returning a bool:

if (!glfwInit())
    throw std::runtime_error("GLFW failed to initialize.");


Also note that if you log something to console then errors should go to std::cerr instead of std::cout:

std::cerr &lt;&lt; "ERROR::GLFW::INIT : GLFW failed to initialize" &lt;&lt; std::endl;


If you properly handle error cases (instead of returning an unused flag to signal an error) then you do not need to repeat clean-up code in your initialization function because dtor will take care of it:

Window::~Window()
{
    if (m_IsInitialized)
        glfwTerminate();

    if (m_Window != nullptr)
        glfwDestroyWindow(m_Window);
}


About m_Window: why it's public? There is almost never a good reason to have a public field. Note that if, for any reason, you have to expose this pointer to the external world then I strongly suggest to use std::shared_ptr, you may also go one step further and implement a custom delete function that will call glfwDestroyWindow() (I think it's much easier to add few assertions in this case then track an access violation because memory has been released somewhere). Also this opens the door to more complex scenarios (for example using std::move() to transfer window ownership to another Window instance).

Jumping back to ctor, you can use an initializer list:

Window::Window(const char* title, int width, int height, bool vsync)
    : m_Title(title),
      m_Width(width),
      m_Height(height),
      m_VSync(vsync)
{
}


It does not really matter for PODs however you may (and should) declare all those members as const (and * const) then you must use this syntax.

You're not validating inputs, that's a bad thing! Is, for example, a negative width allowed? Throw the right exception as soon as possible and you won't need to hunt a bug later.

if (width &lt; 0)
    throw std::invalid_argument("Width cannot be negatie.");