GSI

Posted by gsi
:

단위 전략과 단위 전략 클래스..

예로 들 것은 객체를 생성할때 template를 통해서 new와 malloc를 선택적으로 해주기 위함입니다.
다른 방법들도 몇가지 덧 붙여서 설명하겠습니다.

단위 전략의 설명은 책에 잘 나와 있으니 패스 ^^

우선 단위 전략에 필요한 인터페이스 즉, new, malloc로 구현된 두개의 struct 문입니다.

template < class T >
struct OpNewCreator
{
   static T* Create()
   { return new T }
};

template < class T >
struct MallocCreator
{
   static T* Crate()
   {
      void* buf = std::malloc(sizeof(T));
      if(!buf) return 0;
      return new(buf) T;
   }
};

두개의 단위 전략을 생성 했다면 아래의 단위 전략을 사용할 클래스를 하나 제작 합니다.

template < class CreationPolicy >
class WidgetManager : public CreationPolicy
{
public:
   WidgetManager()
   {
      CTest* p = CreationPolicy().Create();
      ...
   }
   ...
};

어때요?.. 멋지지 않나요?..  CreationPolicy 에 들어 오는 타입에 따른 Create() 를 호출하게 되는 구조입니다.
사용할때는 아래와 같이 적용이 가능해 집니다.

typedef WidgetManager< OpNewCreator<CTest> > MyWidgetMgr;
MyWidgetMgr a;

즉, OpNewCreatorMallocCreator 로 바꾸면 다른 기능을 할 수 있다는 거죠.
이게 바로 단위 전략이라는 거 같네요..

이것을 조금더 자연스럽게 해주는 기능이 또 있습니다.
바로 템플릿 템플릿 인자를 통해서요.
이 설명은 좀더 정리 되면 적도록 하구요..

다른 내용을 주제로 더 적도록 하겠습니다.

위의 단위 전략의 Create() 함수에 다른 인자를 더 넣는건 어떻게 할까.. 고민을 해봤어요.
즉 template 의 인자를 하나더 주자는 예기죠.

아래와 같이 바꾸어 보겠습니다.

template < class T, class U >
struct OpNewCreator
{
   static T* Create( U* u )
   {
      ...
   }
};

이렇게 말이죠. U 의 타입을 받아서 T를 생성한다.
이때는 아래와 같이 타입을 하나더 넣어 주어야 합니다.

typedef WidgetManager< OpNewCreator<CTest, CTest2> > MyWidgetMgr;

이렇게 해서 두개의 타입을 연결하였습니다.
근데 이때, U 에 들어 가는 타입을 디폴트 타입으로 지정하면 어떨까 생각 했죠.

template < class T, class U = CTest2 >
...

이렇게 하면 뒤어 인자를 적어줄 필요가 없게 됩니다.

typedef WidgetManager< OpNewCreator<CTest> > MyWidgetMgr;

바로 이렇게 말이죠.

그렇다면 Create( U* u ) 의 U 인자를 특정 타입으로 특화 하면 어떨까 생각 했죠.

template < class T, class U = CTest2 >
struct OpNewCreator
{
   static T* Create( CTest2* u )
   {
      ...
   }
};

이렇게 하게 되면 WidgetManager 내부에서 제한적인 코딩이 가능해 집니다.
즉, CTest2 의 인자만을 Create()에 집어 넣지 않으면 컴파일 에러가 발생하게 되죠.
다른 인자를 집어 넣는 실수를 막을 수 있을거 같네요.

CTest* p2 = new CTest();
CTest* p = CreationPolicy().Create( p2 );

이렇게 하면 p2가 CTest2가 아니기 때문에 에러가 나게 됩니다. ^^

Tip.
template 를 사용하게 되면 프로그램의 실수를 컴파일 타임에 잡아 주기 위한 기능으로도
적용이 되고 있습니다. 여러사람이 작업을 하거나 제한적인 코딩을 통한 에러를 막기 위한 방법으로
괜찮은 기능인거 같아요.

이상..

잘못된 내용이나 궁금증은 언제든 환영합니다. ^^
Posted by gsi
:

template 를 보고 있는데요.
개인적으로 저에게 가장 많은 생각을 하게 만든건 "Modern C++ Design" 입니다.

현재 1단원만 몇번째 보고 있지만 완전하게 이해 하기가 힘들군요.
하지만 C++ 에서 template 가 왠지 저를 잠못자게 하네요..

특화.. 라는 말을 많이 듣게 되는데요.
가령 예를 들어서 SmartPtr<T>템플릿을 사용하면서, SmartPtr<CTest> 에 대한 모든 멤버 함수를 특화 시킬 수 있습니다.. 이런 말이 나오네요.

제가 이해 하기로는 CTest 함수를 템플릿에 넣어서 특화 시킬 수 있다. 특별하게 처리할 수 있다
전 이렇게 이해가 됩니다...

그렇다면 이번 주제는 함수를 오버로딩하는 건데요.

C++ 에서는 아래와 같이 함수를 오버로딩할 수 있습니다.

void Test(int a) {}
void Test(string a) {}

이런 식이죠.

우선 이것을 지나기 전에 전 기존에 template 가 cpp 쪽의 함수 구현이 어떻게 되어야 하는지 몰랐네요 ^^

헤더 파일에 아래와 같은 클래스와 함수가 있다고 가정을 합시다.

template < class T>
CTest
{
  ...
  void Fun();
};

이렇게 있다고 했을때 cpp 에서는 똑같이 함 적어 볼께요.

template < class T >
void CTest::Fun() {}

아 이렇게 하면 두개의 에러가 나옵니다.
> 함수 정의를 기존 선언과 일치시킬 수 없다와 템플릿 클래스를 사용하려면 템플릿 인수 목록이 있어야 합니다.
이런 에러가 나오게 됩니다.

그래서 조금 다르게 해서 아래와 같이 작성하면 에러가 없어 집니다.

template < class T >
void CTest< T >::Fun() {}


이건 알고 계신다구요?.. -.- 전 이제까지 몰랐답니다. ㅋㅋ..

여기 까지는 대부분 아는 내용일테구요..

이제 여기 까지 하게 되면 멤버 함수 특화 라는 말이 나오게 되요. @.@

이 말도 정말 이해가 안되더군요 ^^..
하지만 특화라는 말은 template 의 T의 성분을 특정 타입으로 지정한다..
이렇게 전 아직 이해 한답니다. <--- 이거 잘못된건지 아시면 꼭 지적 부탁 드려요..

그래서 아래와 같이 함수 특화를 해볼께요..

template <>
void CTest< char >::Fun() {}


이렇게 해서 char 형태로 특화를 했습니다.

이렇게 하고 나면 어떤 현상이 발생 하냐 하면요..

이 클래스를 사용하는 부분에서.

typedef CTest<int> A;
A a;


이렇게 작성했다고 합시다.
우리가 이전에 Fun() 함수는 char 형태로만 특화 되어 있는걸 아시죠?
즉, int 형을 특화 시켰기 때문에 에러가 발생 합니다.

이것만 가지고도 사용자의 실수를 방지 할 수 있는 좋은 수단이 되지요. ^^

그렇다면 내가 원하는 특정한 타입을 T로 받아 들이고 그 타입에 따른 Fun() 함수를 따로 구현하고 싶을때

필요한 타입을 다 제작을 합니다.

template < class T >
void CTest<T>::Fun() {}

template <>
void CTest<char>::Fun() {}

template <>
void CTest<int>::Fun() {}


이렇게 3가지를 구현했습니다.

T의 값이 int, char 일때는 아래 두개의 함수로 분기 되게 됩니다.
그리고 나머지 모든 값은 제일 위의 함수로 분기 되죠.

어때요?.. 전 이거 보고 너무 좋았답니다. ^^

Tip.

위의 3개의 함수를 보시면 위쪽은 class T 가 되어 있는걸 아시겠죠?.
아래는 안되어 있구요..
개인적으로 다 해보세요.. 위와 같이 안하면 에러가 나요 ^^

왜냐구요?.. 아직 잘 모르겠어요 ㅋㅋ.. 아시면 꼭 얘기 부탁 해요.. ^^
Posted by gsi
:

책을 2, 3번 정도 읽으니 조금 이해가 되네요.
아직 100%는 아니지만 ^^

처음에는 템플릿으로 참 알아 보지도 못하는 것을 구현하기에.. 난해 했지만.

지금 조금 이해가 되는 부분에서 느껴 지는 것은
템플릿을 사용해서 컴파일 타임에서 오류를 잡아 주거나,
메모리 생성하는 규칙을 템플릿으로 typedef 잡아서 사용하거나 하는 부분들이
잘만 활용하면 상속 만큼이나 아니면 더 많은 부분을 효과적으로 구현하게
해주는 것인지도 모르겠다.

아래의 예를 잠깐 보면..

// TemplateTest.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//

#include "stdafx.h"

template <class T>
struct OpNewCreator
{
 static T* Create()
 {
  printf("OpNewCreator - new 사용\n");
  return new T;
 }
};

template <class T>
struct MallocCreator
{
 static T* Create()
 {
  printf("MallocCreator - malloc 사용\n");
  void* buf = std::malloc(sizeof(T));
  if(!buf) return 0;
  return new(buf) T;
 }
};

class Widget
{
public:
 Widget() { printf("Widget 생성자 호출\n"); }
 ~Widget();
};

class CTest : public Widget
{
public:
 CTest() { printf("Widget 생성자 호출\n"); }
 ~CTest() {}
};

template < template <class Created> class CreationPolicy >
class WidgetManager : public CreationPolicy< Widget >
{
public:
 WidgetManager()
 {
  Dosomething();
 }

 ~WidgetManager() {}

 void Dosomething()
 {
  CTest* pw = CreationPolicy<CTest>().Create();
 }
};

typedef WidgetManager< OpNewCreator > MyWidgetMgr_New;
typedef WidgetManager< MallocCreator > MyWidgetMgr_Malloc;


int _tmain(int argc, _TCHAR* argv[])
{
 MyWidgetMgr_New a;
 MyWidgetMgr_Malloc b;

 return 0;
}

어쩌면.. 위의 typedef 부분인거 같다.
내가 new를 사용해서 객체를 할당 한다거나 하다가 상황에 따라서 malloc를 사용해야 한다고 하면
코드를 고치기 보다 typedef 부분을 수정해 주므로 모든게 해결이 된다.

아래는 실행된 모습이다.

사용자 삽입 이미지


하지만 여기서 궁금한건...
Widget를 Class 부분에서 미리 정의 해 주는 부분인데.. 잘 이해가 되지 않는다.
Posted by gsi
:

스크롤 뷰와 비슷하게 미니맵을 통한 이미지 뷰어나 기나 에디터 프로그램의 프레임으로 적용할려고 합니다.
드로잉은 동적 컨트롤에 의존 하지 않고 메인 뷰에서 다 처리 하도록 하여 Flicker 현상을 없앨려고 합니다.
미니맵의 베이스 크기만을 적용해 봤기 때문에 아주 심플한 코드 입니다.

사용자 삽입 이미지


관련 코드 :
기본 모델

화면에 보여지는 것만 더 드로잉 해본것..
Canvas 가 이동될때 파란색 사각형(보여지는 부분 표시)의 움직임 처리를 해봐야 할 소스
Posted by gsi
: