Basic DirectX window class As a C++ beginner learning C++ and DirectX at the same time, I was wondering if a more experienced C++ developer would be able to go over the code and tell me what is done incorrectly or something that you would change.

Window.h

#pragma once

#include &lt;string&gt;
#include &lt;windows.h&gt;

namespace Graphics {

class Window
{
private:
    const char *m_Title;
    int m_Width;
    int m_Height;
    HINSTANCE m_hInstance;
public:
    Window(const char *title, int width, int height);
    ~Window();

    bool Init();
    bool CreateD3DWindow();
    void Loop();

    inline int GetWidth() { return m_Width; }
    inline int GetHeight() { return m_Height; }
};
}


Window.cpp

#include "Window.h"

#include &lt;iostream&gt;

namespace Graphics {

// Forward declarations
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

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

Window::~Window()
{

}

bool Window::Init()
{
    if (!CreateD3DWindow())
    {
        return false;
    }

    return true;
}

void Window::Loop()
{
    MSG msg;
    ZeroMemory(&amp;msg, sizeof(MSG));

    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&amp;msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&amp;msg);
            DispatchMessage(&amp;msg);
        }
        else
        {
            // Render
        }
    }
}

bool Window::CreateD3DWindow()
{
    HWND hWnd;
    WNDCLASSEX wc;

    m_hInstance = GetModuleHandle(NULL);

    // Window styling and options
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = m_hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    wc.hIconSm = wc.hIcon;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = m_Title;
    wc.cbSize = sizeof(WNDCLASSEX);

    if (!RegisterClassEx(&amp;wc))
    {
        std::cout &lt;&lt; "RegisterClassEx failed!" &lt;&lt; std::endl;
        return false;
    }

    hWnd = CreateWindowEx(
        WS_EX_APPWINDOW,
        m_Title,
        m_Title,
        WS_OVERLAPPEDWINDOW,
        GetSystemMetrics(SM_CXSCREEN) / 2 - m_Width / 2,
        GetSystemMetrics(SM_CYSCREEN) / 2 - m_Height / 2,
        m_Width,
        m_Height,
        NULL,
        NULL,
        m_hInstance,
        NULL
    );

    if (!hWnd)
    {
        std::cout &lt;&lt; "Failed to create window" &lt;&lt; std::endl;
        PostQuitMessage(0);

        return false;
    }

    ShowWindow(hWnd, SW_SHOW);

    return true;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        return 0;

    case WM_KEYDOWN:
    {
        switch (wParam)
        {
        case VK_ESCAPE:
            PostQuitMessage(0);
            return 0;
        }
    }

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    };

    return 0;
}
}
I have one big swooping recommendation that I feel you should address before tackling anything else:

Mind your class invariants!

When designing a class, ideally you want to ensure every single public member function handles correctly any possible valid state of the class, in conjunction with any possible passed argument. In your case, ask yourself:

What happens if Loop() gets called before Init()? What happens if Init() gets called twice in a row? What happens if Create3DWindow() is called after Init()?

A good way to tackle that is to define what's known as a class invariant. 

First, jot down on paper a description of the legal internal states of the class. That's known as the class invariant.

For example, you may want to have m_hInstance is either NULL or points to a window instance in your invariant definition, but m_hInstance points to a window instance would be even better, because it allows you to rely on that being true, so you don't have to constantly check.

Second, for each public member function, make sure that the function's behavior is well defined for every possible invariant state, and that it leaves the class in an invariant state after it's done. 

Mind you, it doesn't mean that every public member function must "work", just that it doesn't explode, cause memory leaks, etc...

Edit: There are some extreme exceptions to this, such as std::vector&lt;&gt;'s operator[]. But this is an exception, and the class' documentation makes it extremely clear that you enter no-mans land if you call that with an index outside of the bounds.