2013-09-07 6 views
1

최근 C++에서 불투명 포인터에 대해 배웠습니다. 나는 플랫폼 특정 사적인 멤버를 숨기기 위해 그것들을 사용하기 시작했다. <windows.h> 등의 정의에 대한 참조 등C++ 불투명 포인터의 개인 데이터 통신

이제 서로를 구축하고 상호 통신해야하는 몇 가지 시스템이 있습니다. 예를 들어, 윈도우 핸들 (HWND)을 필요로하는 Direct3D. 내 핵심 시스템에 플랫폼 정의를 공개하고 싶지는 않지만 내 하위 시스템은 해당 데이터를 전달해야합니다.

나는 불투명 한 데이터를 노출하고 void 포인터를 통해 액세스 할 수 있습니다. 이렇게하면 모든 개인 데이터에 액세스 할 수 있습니다.

사용 예제 (MAIN.CPP) :

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

윈도우 정의 (시스템/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를 프레젠테이션 매개 변수 (D3DPRESENT_PARAMETERS::hDeviceWindow)

+0

정확히 어떻게이 코드에'HWND'를 저장하고 있습니까?당신이 취할 수있는 접근 방식이 약간 다릅니다. 나는'pImpl' 해결책에 기대고있다. –

+0

Mats, HWND를 포함하는 WindowData 코드를 추가했습니다. 비록 불투명 한 포인터가 pImple 이었지만 ... –

답변

1

내가 getHandle을 할 것 (또는 더 나은 void * 대신 WindowData *을 반환 getWindowData 다음 WindowData은 "시스템/Window.h"파일에 단지 앞으로 선언하자

.

내부 "Direct3D9"는, 그래서, WindowData의 전체 정의를 사용

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

나중에 약간의 단계에서 리눅스로 포팅한다면 WindowData 내부의 완전히 다른 구조를 가질 수 있습니다 [구현 측면에서 어떤 유형의 #ifdef __WIN32/#else 유형을 기반으로합니다].

+0

나는 이것을 원래 시도했다. 그러나,'WindowData'가'Window'에 대한 개인 정보라는 아이디어로 시작했기 때문에 모든 개인 데이터를 노출시키는 것이 옳지 않다고 생각했습니다. 나는 Window를 WindowData에 '친구'로 만들고 Window :: data를 공개적으로 사용할 수있게함으로써이를 해결했다. 이를 통해'Window'가'WindowData'의 private 필드에 접근 할 수 있고 서브 시스템은 public 필드에 접근 할 수 있습니다. 전에 우정을 사용한 적이 없기 때문에 그것이 최선의 해결책인지 잘 모르겠습니다. –

+0

"Window"가 무엇을해야하는지 (또는 어떻게 할 것인가)를 완전히 이해하지 못하면 "최상의"솔루션이 무엇인지 정확하게 말하기가 어렵습니다. 일반적으로 우정은 제한되어야합니다. 올바른 것을 제공하는 함수를 노출하는 것이 낫습니다. 예 : '_window.GetWindowData() -> GetHandle()', 아마도? –

+0

Window는 GUI 창을 생성하고 표시하는 클래스입니다. 내부적으로 플랫폼 특정 코드를 구현하는 동안 내 'System'네임 스페이스의 모든 것이 문서화 된 외부 인터페이스를 구현합니다. 아이디어는'WindowData'는'Window'의 "확장"입니다. 각 "pImpl"이 그 소유자에게 '친구'인 "소유자"를 갖고 있다는 것은 문제가 아닌 것처럼 보입니다. '_window.GetWindowData() -> GetHandle()'은 너무 많은 추상화 레이어를 추가하는 것처럼 보입니다. 그러나'WindowData'에서 구현하는 것은 종속성을 제한하기 위해 타입 안전성과 권한을 추가로 필요로합니다. 접근자는 그 역할을 채우는 것처럼 보입니다. –

-1

당신은 데이터를 복사하고 unique_ptr을 반환 할 수 있습니다에 다이렉트에 의해 사용된다. 또는 HWND를 HWND 대신 void *로 반환 할 수 있습니다. 실제로 포인터를 사용하기 때문에 구현을 실제로 활용할 수 있습니다. 그러나 마음에 계속, 다른 사람들은 여전히 ​​HWND를 통해 어떻게 든 창을 바꿀 수 있으며, 당신이 그것에 대해 할 수있는 일이별로 없다고 생각합니다.

+0

질문은 ** 실제 데이터를 숨기지 않고 ** 플랫폼 관련 구현 세부 사항을 추상화하는 것에 관한 것입니다. – IInspectable

+0

Cooky451, 당신은 HWND에 대해 정확합니다.별로 보호 할 수는 없습니다. 위의 예제에서'(void *) '를 사용하고 있습니다. 그러나, 주물은 복잡하게된다. 다른 불투명 포인터로 출력을 래핑하는 실험을 해왔지만 아직 얻지 못했습니다. 많은 작은 구조체/클래스를 랩핑하는 것이 좋은 디자인인지 잘 모르겠습니다. –

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()) 
{ 
} 
+0

정교하게 말하면 이해할 수 없거나 상식입니다. 나는 전체 화면, 최소/최대화 창 등을 토글하는 것과 같은 다양한 액션을 구현하고있다. 그러나 다른 서브 시스템은'HWND','LPDIRECT3DDEVICE9', 오디오 I/O 핸들 등을 필요로 할 수도있다. 나는 노출하고 싶지 않다. 그것들은 내 "코어"에 있지만 서브 시스템이 그것을 액세스 할 수있게 해줍니다. –

+0

필자는 자체 윈도우 시스템을 구현하지는 않았지만 이전에는 다양한 운영 체제/플랫폼을위한 스레딩 라이브러리, TCP/UDP/직렬 통신 라이브러리를 구현/캡슐화했습니다. 이러한 노력을하는 동안 HWND/Thread 핸들 등을 노출 할 필요가 전혀 없습니다. 변화하는 개념을 캡슐화하십시오. 핸들을 공유해야하는 경우 특정 "기능적"책임 측면에서 공유해야합니다. –

+0

책임/요구 사항은 핸들이 있는지 여부에 관계없이 존재합니다 (일부 플랫폼에서는 그렇지 않습니다). 핸들을 공유해야하는 경우 책임을 정의하는 인터페이스를 통해 핸들을 공유하십시오. 결국 모든 인터페이스는 하나의 구현에서 절정에 달하고 각 공유자는 shared_ptr을 통해 정의 된 책임 (또는 인터페이스) 측면에서 핸들을 공유합니다 (shared_ptr 을 통해). –