使用名称空间代替类
我正在设计一个接口来抽象管理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
文件中包含#include
的文件中时。 我非常喜欢这个。
名称空间方法似乎是最好的方法,但是在嵌套的未命名名称空间内处理变量的方式中,某些事情并不完全与我保持一致。 这是一个好习惯吗? 我的直觉告诉我没有! 没有! 没有!
所以我想我的问题是: 这是一个适用于名称空间的用例吗?
澄清:我已经在WindowsApp.cpp中定义了未命名的命名空间以及函数定义 - 所有函数的前向声明都在WindowsApp.h中 - 通过调用这些函数来操作未命名的命名空间中的变量。 这是命名空间的一个不好的用法,还是应该以不同的方式完成? 只需将头文件包含在任何其他.cpp文件中,您就可以访问这些函数,并依次访问底层数据。 这非常有吸引力。 我的直觉告诉我,这样的结构会产生某种性能损失。
[ 编辑 :删除关于未命名的命名空间的东西开始为TU所独有,现在问题中的代码已被澄清。]
在C ++中,我们倾向于将一个class
看作是一些数据的包装,它保持一个不变量(与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
实例。
上一篇: Using A Namespace In Place Of A Class
下一篇: Namespace technique in JavaScript having issues in JSLint