아 이것 참 귀가 간지러울때 귀후비개가 없어서 속을 썩이는 것 마냥
그렇게 귀찮은 존재가 아닐수 없었다.

캡슐화와 template class와에 관계는 물과 기름에 성격이 강하다.
캡슐화를 위해서는 최대한 블랙박스 형태로 코드를 작성해야 하지만 template에 특성상 타입이 모두 공개되야 함으로 이렇게 할 수 없게 된다.
 
특히 내부에서 사용하는 container로 STL을 이용하는 경우
클래스 멤버로 STL을 사용하는 경우는 선언부에서 정의부로 옮겨서 작성하면 그나마 좀 더 쉽다.
FROM
test.h
class ctest {
  vector<int> container ;
} ;

TO
test.h
class ctest {
  ctest() ;
  //vector<int> container ; //=> .cpp로 이동
} ;

test.cpp
vector<int> container ;

ctest::ctest() {}
...

하지만 함수에 리턴값이나 파라미터로 STL이 사용되는 경우에는 어쩔수 없이 선언부에 STL이 포함될 수밖에 없다.

class ctest {
  vector<int>::iterator first( void )   {
    return container.begin() ;
  }
  vector<int>::iterator next( vector<int>::iterator pos ) {
    ...
    pos++ ;
    return pos ;
  }
 ...
} ;

바로 이부분이 STL을 사용한 클래스 작성시 항상 눈에 거슬리던 부분으로 어떻게 함수 프로토타입에서 내부 정보를 더 숨길 수 있냐는 것이었다.
return type으로 vector라는 type 정보가 보임으로써 test라는 클래스를 사용할때 이미 내부 정보를 알수 있게 되었을 뿐만 아니라 test class를 사용하는 곳에서는 vector에 특화되게 코드가 작성될 빌미를 제공하게 된다.
이것은 내부 container를 변경해야 하는 경우 문제가 심각해진다.
클래스 내부에 수정은 클래스를 사용하는 외부까지 수정을 요하게 될 것이고 이것은 수정은 물건너 갔다는 말이 된다.

그렇다면 어떻게 공개되어 있는 타입 정보를 숨길수 있을까?
방법은 distance와 advance이다.
즉 iterator를 리턴하는 곳에서 distance를 이용해서 begin에서 pos까지에 difference로 변환하는것이다.
사용하는 곳에서는 역으로 advance를 이용해서 difference에서 iterator로 변환해서 사용하면 된다.

class ctest {
  int first( void )   {
    return 0 ;
  }

  int next( int pos ) {
    vector<int>::iterator iter = container.begin() ;
    advance( iter, pos ) ;
    ...
    ++pos ;
    return distance( container.begin(), pos ) ;
  } ;

 ...
} ;

이렇게 함으로써 함수에 프로토타입에서 내부  자료형을 모두 숨김으로써 유지보수가 쉬워질 뿐만아니라 컨테이너를 변경할 경우 사용하는곳(client)을 신경쓰지 않아도 되는 장점이 생긴다.

아 앓던 이가 빠진 기분이다. 가슴이 다 뻥뚤리는구만~

EOF

+ Recent posts