본문 바로가기
Programming/Tips(C++,C#)

Chapter 3. 인터페이스

by 곰네Zip 2014. 10. 27.

*이 포스팅은 개인 학습을 위해 내용을 정리한 것이 목적입니다.

 

*인터페이스 : COM에 있어서 클라이언트들이 COM자신에게 접근 가능한 통신채널을 제공하는 것

 

1. 개략적인 인터페이스

 - DLL에 대한 인터페이스 : DLL에 의해 노출되는 함수들의 집합

 - 클래스에 대한 인터페이스 : 클래스 멤버들의 집합

 - COM인터페이스 : 변화에 의한 손상으로부터 시스템을 보호할 수 있고, 다른 컴포넌트에 대해 클라이언

  트가 동일한 방법으로 접근할 수 있도록 함.

  COM인터페이스는 함수에 대한 포인터들의 배열을 포함하는 특정한 메모리 구조.

 - C++에서 COM 인터페이스 구현

   이진 표준을 따르기 위해 추상 기본 클래스를 이용하여 인터페이스를 만들고, 하나의 컴포넌트는 여러개

  의 인터페이스를 제공할 수 있으므로, 추상 기본 클래스로부터 다중 상속을 받아 인터페이스를 만들어야

  한다.

 - COM은 인터페이스를 통하여 외부와의 연결통로를 제공하고, 구현 부분을 완전히 캡슐화 함

 - 인터페이스와 구현을 분리한 목적

   1) 프로그래밍 언어에 대한 독립성

     COM객체는 COM이 규정하는 바이너리 레이아웃을 지원하는 어떤 언어로도 프로그래밍 가능

   2) 재사용성

     COM객체는 캡슐화 되고, 자신의 구현은 인터페이스와 분리됨

   3) 상호운용성

     여러 어플리케이션과 객체 사이에서 동일한 방식으로 사용될 수 있다.

   4) 위치투명성

     COM객체는 위치에 구애받지 않는다

   5) 독립적, 비 공동적 확장성

     COM객체는 확장성을 가지고 있어, 기존 버전을 침해하지 않고 버전업 가능

   6) 배포성

     COM객체는 그 자체로 갖추어진 재사용이 가능한 컴포넌트이므로 쉽게 배포하여 사용가능

   7) 효율성

     COM객체는 작고, 가볍고, 빠르다.

 

2. COM인터페이스의 구현

  COM인터페이스의 구현은 추상 기본 클래스를 바탕으로 구현.

 아래 예는 COM을 고려하지 않은 클래스. 

 #include <iostream.h>

 

 class CSimpleCalc{

     int x;

     int y;

 public:

     CSimpleCalc(int x1, int y1){

       x = x1;

       y = y1;

     }

     int sum(){ return x+y; }

     int sub(){ return x-y; }

 }

 

 void main(){

    int x1, y1;

    cout << "Input x" << endl;

    cin >> x1;

    cout << "Input y" << endl;

    cin >> y1;

   

    CSimpleCalc sc(x1,y1);

    cout << "x+y " << sc.sum() << endl;

    cout << "x-y" << sc.sub() << endl;

 

 }

  위 소스에서 sum(),sub()에 대해 순수 가상함수를 선언한 추상 클래스를 만들자. 

 #include <iostream.h>

 #include <objbase.h>

 

 interface ISimpleCalc{

    virtual int __stdcall sum() = 0;

    virtual int __stdcall sub() = 0;

 }

 

 class CSimpleCalc : public ISimpleCalc{

     int x;

     int y;

 public:

    CSimpleCalc(int x1, int y1){

        x = x1;

        y = y1;

    }

    virtual int __stdcall sum(){ return x+y; }

    virtual int __stdcall sub(){ return x-y; }

 };

 

 void main(){

    int x1, y1;

    cout << "input x" << endl;

    cin >> x1;

    cout << "input y" << endl;

    cin >> y1;

    CSimpleCalc* pSc = new CSimpleCalc(x1,y1);

    ISimpleCalc *pISc = pSc;

    cout << " sum = " << pISc->sum() << endl << "sub = " << pISc->sub() << endl;

    delete pSc;

 }

 위 녹색 키워드 interface는 struct로 정의된 키워드이다. (objbase.h에 정의되어있음)

 구조체를 기본으로 구성하면 리턴 값을 pascal로 해아 하므로 __stdcall 함수를 호출해야 한다.

 

3. 인터페이스 탐구

 인터페이스는 그 객체와 그 객체를 사용하는 프로그램간의 약속. 인터페이스에 의해 노출된 멤버에 대해서 클라이언트는 항상 사용할 수 있다. 또한, 인터페이스는 버전업이 되어도 계속 유지되어야 한다.

  1) 가상함수 테이블

   순수 추상 클래스를 정의하는 것은 실제로 메모리의 블럭을 정의하는 것과 동일하다.

   이 메모리 블럭은 Virtual Function Table과 이 테이블에 대한 포인터 두 부분으로 구성된다. COM인터페

  이스에 대한 메모리의 배치는 추상 기본클래스의 메모리 배치와 일치

   인스턴스데이터의 경우 잠정적으로 클래스 포인터를 통해 접근이 가능하다.  그러나 클라이언트에서는 이

  러한 방법에 대해 알지 못하므로, 접근이 불가능하다. 그래서 COM에서는 함수를 통해서만 조작이 가능.

 

  2) 객체지향

    COM은 객체지향의 특성을 그대로 구현한다.

 

  3) 버전문제의 해결

    *인터페이스는 계속 유지되어야 한다. 즉, 인터페이스가 추가/변경되어야 할 때에는 기존의 인터페이스

    를 변경하지 말고 신규 인터페이스를 추가해야 한다.

     (처음에 인터페이스 설계를 잘 해야하는거.. 아니면 한 함수에 대해 파라미터 붙고 붙어서... 기능적으로는 하나의 함수인데 인터페이스가 몇개씩 나오는 그래서 인터페이스 이름이 blabla1, blabla2,  blabla_full등.. 이상한 이름을 가지는 참사도 일어나더라. -_ -; )

   

    * COM클라이언트 입장에서, COM 컴포넌트가 가지고 있는 인터페이스를 알 방법이 없다. 이러한 인터

     페이스를 얻기 위해 QueryInterface를 사용한다. 이것은 모든 COM객체가 가진 IUnknown인터페이스

     선언된 함수이다. IUnknown은 AddRef(), Release(), QueryInterface()로 구성되어있다. 다음 챕터에서

     더 자세히..

 

내용 출처 : COM Bible

반응형

댓글