Using A Namespace In Place Of A Class

I'm designing an interface to abstract the tasks of managing Direct3D, Direct2D, DXGI, and the associated Win32API calls.

Keep everything inside a namespace or refactor to use a class?

WindowsApp.h

#pragma once
#include <Windows.h>

namespace WindowsApp
{
    bool Initialize(HINSTANCE instanceHandle);
}

WindowsApp.cpp

#include "WindowsApp.h"

namespace WindowsApp
{
    namespace
    {
        HWND ghMainWnd = 0;
    }

    LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
        break;

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

    bool Initialize(HINSTANCE instanceHandle)
    {
        WNDCLASS wc;
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = instanceHandle;
        wc.hIcon = LoadIcon(0, IDI_APPLICATION);
        wc.hCursor = LoadCursor(0, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName = 0;
        wc.lpszClassName = L"BasicWndClass";

        if (!RegisterClass(&wc))
        {
            MessageBox(0, L"RegisterClass FAILED", 0, 0);
            return false;
        }

        ghMainWnd = CreateWindow(
            L"BasicWndClass",
            L"Win32Basic",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0,
            0,
            instanceHandle,
            0);

        if (ghMainWnd == 0)
        {
            MessageBox(0, L"CreateWindow FAILED", 0, 0);
        }

        ShowWindow(ghMainWnd, 1);
        UpdateWindow(ghMainWnd);

        return true;
    }
}

Main.cpp

#include "WindowsApp.h"

int Run()
{
    MSG msg = { 0 };

    BOOL bRet = 1;
    while ((bRet = GetMessage(&msg, 0, 0, 0)) != 0)
    {
        if (bRet == -1)
        {
            MessageBox(0, L"GetMessage FAILED", L"Error", MB_OK);
            break;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    // Deinitialize Here
    return (int)msg.wParam;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
    if (!WindowsApp::Initialize(hInstance)) { return 0; }
    return Run();
}

Using a namespace allows me to hide implementation details inside the nested unnamed namespace. A class wont let me hide things but I can make them inaccessible inside the private section, that's good enough I suppose.

Using a class runs the risk of users trying to instantiate multiple objects, which, would cause the application to crash from initializing DirectX twice or something. Namespaces avoid this issue however they present a performance degrading factor, I have to check the Initialized variable during each function call. I really dislike this.

Finally using a class requires the user to pass around the instantiated object throughout the application wherever the underlying methods are needed. That is really disappointing since the namespace approach gives me access whenever I'm inside a file that's got an #include to the namespaces header file. I really like this.

The namespace approach seems like the best way to go but something doesn't quite sit right with me in the way variables are handled inside the nested unnamed namespace. Is that an okay practice? My gut is telling me no! no! no!

So I guess my question would be: Is this an appropriate use-case for namespaces?

For Clarification: I've got the unnamed namespace defined inside WindowsApp.cpp along with the function definitions - forward declarations to all the functions are inside WindowsApp.h - Through use of calling these functions manipulates the variables inside the unnamed namespace. Is this a bad use of namespaces or should it be done a different way? Simply including the header file in any other .cpp gives you access to the functions and in turn the underlying data. This is very appealing. My gut tells me there is some kind of performance penalty that will ensue from structuring like this.


[ EDIT : Remove stuff about unnamed namespaces begin unique to TUs now the code in the question has been clarified.]

In C++ we tend to think of a class as being a wrapper for some data which maintains an invariant (as opposed to a struct , which tends to be used for a bunch of data with no invariant). The constructor establishes the invariant, the destructor tears it down, and the member functions are careful to maintain it. Here, if I've understood correctly, it seems like your invariant is that Initialized() must called prior to using any other API function.

There is another alternative, which is to use so-called "magic statics", otherwise known as "Meyers singletons". Do something like the following:

// In WindowsApp.cpp

namespace {

class WindowsAppImpl {
public:
    WindowsAppImpl()
    {
        // Do initialization stuff here
    }

    ~WindowsAppImpl()
    { 
        // Do teardown stuff if necessary
    }

    // Example function
    int getMagicNumber()
    {
        return 3;
    }
};

WindowsAppImpl& GetInstance() {
    static WindowsAppImpl instance{};
    return instance;
}

} // end private namespace

// Public function declared in WindowApp.h
int GetMagicNumber() {
    // Get the singleton instance
    WindowsAppImpl& instance = GetInstance();

    // Call member function
    return instance.getMagicNumber();
}

This approach adds a function which returns a reference to the singleton WindowsAppImpl instance. The compiler guarantees that this instance is constructed exactly once, the first time GetInstance() is called. (It will also run the destructor for WindowsAppImpl after main() has finished, which is probably not important in this case but can be useful in some cases.) The advantage of this approach is that inside GetMagicNumber() you can be sure the initialization routines have been run, without requiring the user to pass around some sort of WindowsAppContext instance of their own.

链接地址: http://www.djcxy.com/p/17048.html

上一篇: Javascript中的命名空间问题

下一篇: 使用名称空间代替类