簡體   English   中英

使用命名空間代替類

[英]Using A Namespace In Place Of A Class

我正在設計一個接口,以抽象化管理Direct3D,Direct2D,DXGI和關聯的Win32API調用的任務。

將所有內容保留在名稱空間中還是重構以使用類?

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();
}

使用名稱空間可以使實現細節隱藏在嵌套的未命名名稱空間中。 一堂課不會讓我隱藏東西,但是我可以使它們在私有區域中無法訪問,我想這已經足夠了。

使用類會冒着用戶嘗試實例化多個對象的風險,這將導致應用程序因兩次初始化DirectX或類似事件而崩潰。 命名空間避免了這個問題,但是它們會帶來性能下降的因素,我必須在每次函數調用期間檢查Initialized變量。 我真的不喜歡這個

最后,使用類要求用戶在需要基礎方法的任何地方在整個應用程序中傳遞實例化的對象。 這真令人失望,因為無論何時我進入名稱空間頭文件中包含#include的文件時,名稱空間方法都使我能夠訪問。 我真的很喜歡

命名空間方法似乎是最好的方法,但是在嵌套的未命名命名空間中處理變量的方式與我不太一致。 這樣可以嗎? 我的直覺告訴我不! 沒有! 沒有!

所以我想我的問題是: 這是名稱空間的適當用例嗎?

為了澄清起見:我在WindowsApp.cpp中定義了未命名的名稱空間以及函數定義-向所有函數的轉發聲明都在WindowsApp.h中-通過調用這些函數來操縱未命名的名稱空間中的變量。 這是對名稱空間的不良使用還是應該以其他方式進行? 只需將頭文件包含在任何其他.cpp文件中,就可以訪問函數,並依次訪問基礎數據。 這很吸引人。 我的直覺告訴我,這樣的結構會導致某種性能損失。

[ 編輯 :現在,已澄清問題中的代碼,刪除有關未命名名稱空間的內容對於TU來說是唯一的。

在C ++中,我們傾向於將class視為某些保持不變的數據的包裝器(與struct相對,而struct通常用於沒有不變性的一堆數據)。 構造函數建立不變量,析構函數將其拆下,並且成員函數要小心維護它。 在這里,如果我正確理解,似乎您的不變之處在於必須在使用任何其他API函數之前調用Initialized()

還有另一種選擇,即使用所謂的“魔術靜態”,也稱為“邁耶單子”。 執行以下操作:

// 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();
}

此方法添加了一個函數,該函數返回對單例WindowsAppImpl實例的引用。 編譯器保證在第一次GetInstance()時,只構造一次該實例。 (它還將在main()完成之后運行WindowsAppImpl的析構函數,這在這種情況下可能並不重要,但在某些情況下可能有用。)此方法的優點是,可以在GetMagicNumber()內部確保初始化例程已運行,而無需用戶傳遞自己的某種WindowsAppContext實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM