Ich entwerfe eine Schnittstelle, um die Aufgaben der Verwaltung von Direct3D, Direct2D, DXGI und den zugeordneten Win32API-Aufrufen zu abstrahieren.Verwenden eines Namespaces anstelle einer Klasse
Behalten Sie alles in einem Namespace oder Refactor, um eine Klasse zu verwenden?
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();
}
eine namesp Verwendung Mit ass kann ich Implementierungsdetails im verschachtelten unbenannten Namespace ausblenden. Eine Klasse lässt mich nicht Dinge verstecken, aber ich kann sie innerhalb der privaten Abteilung unzugänglich machen, das ist gut genug, nehme ich an.
Die Verwendung einer Klasse birgt das Risiko, dass Benutzer versuchen, mehrere Objekte zu instanziieren, was dazu führen würde, dass die Anwendung zweimal von DirectX initialisiert wird. Namespaces vermeiden dieses Problem, aber sie stellen einen Leistungsminderungsfaktor dar. Ich muss die Initialized
Variable bei jedem Funktionsaufruf überprüfen. Ich mag das wirklich nicht.
Schließlich erfordert die Verwendung einer Klasse, dass der Benutzer das instanziierte Objekt überall in der Anwendung umgeht, wo auch immer die zugrunde liegenden Methoden benötigt werden. Das ist wirklich enttäuschend, da der Namespace-Ansatz mir Zugriff gibt, wenn ich mich in einer Datei befinde, die einen #include
in der Namespace-Header-Datei hat. Das gefällt mir wirklich gut.
Der Namespace-Ansatz scheint der beste Weg zu sein, aber etwas stimmt nicht ganz mit mir in der Art überein, wie Variablen innerhalb des verschachtelten unbenannten Namespaces behandelt werden. Ist das eine gute Übung? Mein Bauch sagt mir nein! Nein! Nein!
Also ich denke, meine Frage wäre: Ist das ein geeigneter Anwendungsfall für Namespaces?
Zur Klarstellung: - vorwärts Erklärungen zu allen Funktionen sind innerhalb WindowsApp.h - ich die unbenannte Namespace in WindowsApp.cpp zusammen mit den Funktionsdefinitionen definiert haben Durch die Verwendung dieser Funktionen aufzurufen manipuliert die Variablen innerhalb der unbenannter Namespace Ist das eine schlechte Verwendung von Namespaces oder sollte es anders gemacht werden? Wenn Sie einfach die Header-Datei in eine andere .cpp-Datei einfügen, erhalten Sie Zugriff auf die Funktionen und damit auf die zugrunde liegenden Daten. Das ist sehr ansprechend. Mein Bauchgefühl sagt mir, dass es eine Art von Leistungsstrafe geben wird, die sich aus der Strukturierung ergeben wird.
klingt für mich, als ob Sie ein Singleton-Muster suchen – vu1p3n0x
Auf den ersten Blick tut es. Dieses Namespacemuster klingt wie der bessere Ansatz, dem ich laut bin, Variablen im verschachtelten unbenannten Namespace zu deklarieren und dann über die Funktionen, die im übergeordneten Namespace definiert sind, darauf zuzugreifen. Nicht ein instanziiertes Klassenobjekt um die Anwendung zu übergeben, nur um Zugriff auf die Member-Funktionen zu bekommen, scheint überflüssig, wenn man die Datei, die alle Forward-Deklarationen für die Namespace-Funktionen enthält, einfach "einschließen" kann. – KKlouzal
Sie müssen nicht unbedingt überall eine Instanz übergeben, die einzelne Instanz konnte statisch abgerufen werden 'WindowsAppClass :: getInstance()' – vu1p3n0x