ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [15] - COM object
    Graphics 2021. 7. 19. 16:43

    여기까지 개념을 비롯한 이론을 알았으면 Graphics Pipeline을 시작해야 합니다. 그러나 배웠던 것은 OpenGL ES이고 하고 싶은 건 DirectX이기 때문에 다시 여기로 돌아올 수밖에 없습니다. ChiliFrameWork를 토대로 D3D를 활용하는 아주 기본적인 내용을 익혔습니다. 이제 본격적으로 Microsoft에서 제공하는 COM object를 비롯한 내용을 익혀나갈 것입니다. 

    다행히 COM을 완전히 그리고 완벽히 이해할 필요는 없습니다. 대부분의 내용은 몰라도 사용할 수 있다고 합니다. 그래도 기본은 알고 넘어가는 편이 좋습니다.

    이를 위해서는 Binary Compatability에 대해서 알고 가는 편이 좋겠습니다.

    C++는 기본적으로 바이너리 데이터에 대한 마땅한 지시가 없기 때문에 소프트웨어의 요소들을 다시 사용할 때 컴파일 된 바이너리 오브젝트[Binary Object]를 사용하기 보다는 Class나 Source Code를 사용합니다. 

     

     

    반면에 Incompatable하다는 것은 상황이나 기계에 따라 어떤 소프트웨어가 동작하지 않을 가능성을 말하는 것입니다. 단적인 예를 들면 MSVC와 GCC Compiler가 Virtual Function Table에 대한 포인터의 관리가 있습니다. MSVC는 가상 함수 테이블에 대한 포인터를 오브젝트 머리에 두지만 GCC Compiler는 오브젝트의 꼬리에 둡니다. 이런 상황에서 두 컴파일러가 *.dll에 있는 Something class의 한 method를 사용하고 싶다면 해당 method의 헤더파일을 불러오고 인스턴스를 만들면 생성자가 메모리에 initialising을 해줄 것입니다. 이때, 메모리에 할당을 줄 때, 이 Something method를 머리에 만들어 주게 될 경우 GCC compiler는 이 method가 꼬리에 있을 것으로 예상하고 virtual method dynamic dispatch를 실시해서 이 가상함수를 Resolve해보려고 하지만 정의되지 않은 행동을 할 가능성이 높습니다. 왜냐면 사실 메모리 공간의 머리에 해당 함수가 존재하기 때문입니다. MSVC와 GCC는 같은 Binary를 참조하더라도 기대하는 바가 서로 다릅니다.

    그래서 COM object는 이런 상황을 최대한 피하고자 하는 바람에서 만들어졌습니다. 즉, Binary Level에서도 Reusable한 소프트웨어 오브젝트를 제공하는 것이 목표입니다. 어떠한 상황에서도 소스 코드에 접근할 필요도 없고 컴파일을 다시 실시할 필요조차 없게 하여 안정적인 인터페이스를 제공하기도 합니다. 

    간단한 예제입니다. 현재 활성화 되어 있는 Windows의 바탕화면의 파일 이름과 경로를 콘솔에 출력합니다. 

    원래는 COM의 System을 사용하기 위해서는 이처럼 CoInitialize()함수를 호출해야 합니다. 그러나 D3D는 COM이 아니라 Light weight COM을 사용하기 때문에 COM의 Subsystem을 실행하는 것 자체가 필요하지 않습니다.

     

     

     

     

     

     

    Interface

    인터페이스는 COM의 기본적인 개념과 일맥상통 합니다. COM은 깊게 파면 끝이 없는 것 같습니다. 너무 무서우니 당장은 필요한 만큼만 아는 편이 좋을 것 같습니다. 정의에 의하면 Interface는 어떤 특정 Class의 Implementation을 해치지 않는 선에서 C++ Class의 행동 따위를 묘사합니다. Interface는 Abstract Class 기법을 사용하는데 Data Abstraction과 혼동해서는 안됩니다. 순수 가상 함수[Pure Virtual Function]를 포함하면서 Class는 Abstract해집니다.

    Interface는 일반적인 inheritance와 차이가 있습니다. 가령, 어떤 게임 상에 존재하는 상자와 문, 몬스터들은 모두 Punch가 가능합니다. 따라서 디자인을 다음과 같이 하면 문제가 발생합니다.

    Punch라는 함수는 주먹으로 뚜드려 팰 수 있는 것들을 받습니다. 그게 가능한 오브젝트들을 정말 많습니다. 어떤 보물상자 역시 주먹으로 팰 수 있고 적들 역시 팰 수 있습니다. 그래서 이들이 모두 Punch의 특성을 갖는다고 Punchable이라는 BASE CLASS를 만들어 상속을 시켰다고 가정합니다. 그러나 잘 생각해보면 상자는 주먹으로 뚜드려 팰 수도 있으면서 동시에 살며시 열어볼 수도 있습니다. 이는 문[Door]도 마찬가지 입니다. 그러면 Door도 Punchable을 상속 받게 하고 Open할 수 있는 기능을 넣어야 할까요? 그럼 적 몬스터들도 열 수 있어야 하는데 그건 좀 이상할 것입니다.

    보통 이런 경우에 Interface라는 규약을 도입합니다. Puchable이나 Openable이라는 Base class를 Pure Virtual Function을 포함한 Abstract class로 만드는 겁니다.

    이렇게 만들면 곤란할 일이 적어집니다. OpenThat함수는 Openable의 interface를 받은 모든 오브젝트를 열 수 있습니다. 마침 C++는 여러 개의 상속을 받을 수 있기 때문에 이러한 성질을 이용하여 Chest class가 open과 punch 모두 가능한 오브젝트가 되었습니다. 아주 재밌습니다. C#과는 다소 차이가 있습니다. 애초에 C#에는 Interface가 존재하는 모양입니다.

    일반적인 장점은 무엇이 있을까요? 이런 구조를 사용하면 새로운 개념이나 오브젝트가 도입이 되어도 금방 적응시킬 수 있다는 장점이 있습니다. 정말 그럴까요?

     

     

     

     

     

     

     

    'Graphics' 카테고리의 다른 글

    [17] - Device Init  (0) 2021.07.20
    [16] - Swap Chain  (0) 2021.07.19
    [14] - Vertex processing - 2  (0) 2021.07.17
    [13] - Vertex processing - 1  (0) 2021.07.15
    [12] - Space and transforms - 2  (0) 2021.07.14
Designed by Tistory.