архитектура — C ++ Передача личных данных из непрозрачного указателя

Недавно я узнал об непрозрачных указателях в C ++. Я начал использовать их, чтобы скрыть частных участников, которые являются платформенными. Такие как ссылки на определения в <windows.h> и т.п.

Теперь у меня есть несколько систем, которые строятся друг на друге и должны взаимодействовать. Например, Direct3D нужен дескриптор окна (HWND). Я не хочу предоставлять определения платформы моей базовой системе, однако мои подсистемы должны передавать эти данные.

Я выставляю непрозрачные данные и разрешаю доступ через пустой указатель. Это позволяет получить доступ ко всем частным данным.

Пример использования (main.cpp):

// System:: namespace is my platform specific code
System::Window window;
System::DirectX::Direct3D9 gfxcontext(window);

Определение окна (System / Window.h):

class Window
{
WindowData* data; // Opaque pointer
public:
void* getHandle() const; // returns an HWND handle
Window();
~Window();
}

Как получить полезные данные (Direct3D9.cpp):

#include "Window.h"
Direct3D9::Direct3D9(const Window& _window)
{
HWND windowHandle = *(HWND*)_window.getHandle();
// [...]
pp.hDeviceWindow = windowHandle;
}

Однако этот код работает!

*(HWND*)_window.getHandle() = 0; // changes HWND in WindowData to NULL!

Есть ли способ передать информацию о платформе между подсистемами, не подвергая ее независимому коду и сохраняя конфиденциальность личных данных?


редактировать текущая реализация WindowData

struct Window::WindowData
{
static LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
HWND windowHandle;
WNDCLASSEX windowClass;
HINSTANCE processInstance;
};

HWND используется DirectX в параметрах презентации (D3DPRESENT_PARAMETERS::hDeviceWindow)

1

Решение

Я бы позволил getHandle (или лучше getWindowData вернуть WindowData * вместо void *, Тогда пусть WindowData быть просто предварительным объявлением в файле «System / Window.h».

Внутри «Direct3D9» используйте полное определение WindowData, так:

HWND hwnd = _window.getWindowData()->windowHandle;

Если на более позднем этапе вы портируете на Linux, вы можете иметь совершенно иную структуру внутри WindowData [основано на некоторых #ifdef __WIN32/#else тип структуры на стороне реализации.

1

Другие решения

Определите функционально, что вам нужно сделать, а затем реализуйте его с точки зрения интерфейса. Не выставляйте (обнародуйте) указатель. После этого реализуйте интерфейс в терминах HWND и API конкретной платформы.

например:

struct WindowHandleImpl
{
virtual void show() = 0;
virtual void maximize() = 0;
//etc...
};

struct Win32WinHandleImpl : WindowHandleImpl
{
std::unique_ptr<HWND> handle_; //Use deleter...
virtual void show(); //In terms of HWND, using Win32 API
virtual void maximize();
};

struct XWinHandleImpl : WindowHandleImpl
{
//In terms of platform specific handle.
};

struct Window
{
void show(); //In terms of WindowHandleImpl
void maximize();//In terms of WindowHandleImpl
private:
std::unique_ptr<WindowHandleImpl> pimpl_;
};

Window::Window( const Factory& factory )
: pimpl_( factory.createWindow() )
{
}
//or
Window::Window()
: pimpl_( SystemFactory::instance().createWindow() )
{
}
1

Вы можете скопировать данные и вернуть unique_ptr. Или вы можете просто вернуть HWND как void * вместо HWND *, так как в любом случае это просто указатель, хотя это действительно использует реализацию. Имейте в виду, однако, что другие все же могут каким-то образом изменить ваше окно через HWND, и я думаю, что вы ничего не можете с этим поделать.

-1
По вопросам рекламы [email protected]