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
:

MFC 에서 ListBox 에 내용을 추가 하는 코드로 테스트 해본겁니다.

void UTRACE(char* fmt...)
{
 //CString output;
 CTime time = CTime::GetCurrentTime();

 std::ostringstream outstream;
 outstream << "[" << time.GetHour() << ":" << time.GetMinute() << ":" << time.GetSecond() << "] ";

 va_list ap;            //argument pointer

 char*p; int ival; double dval;
 char pBuf[256];  // 버퍼용

 va_start(ap, fmt);        //make ap point to the final named arg
 for(p=fmt; *p; p++) {
  if(*p !='%'){
   outstream << *p;
   //putchar(*p);
   continue;
  }

  switch(*++p){
    case 'd':
     ival = va_arg(ap, int);        //get the argument and move on to the next
     outstream << ival;
     /*itoa(ival, pBuf, 10);
     for(int i=0 ; i < (int)strlen(pBuf) ; i++)
     {
      putchar(pBuf[i]);
     }*/
     break;

    case 'f':
     dval = va_arg(ap, double);        //get the argument and move on to the next
     outstream << dval;
     /*dval = atof( pBuf );
     for(int i=0 ; i < (float)strlen(pBuf) ; i++)
     {
      putchar(pBuf[i]);
     }*/
     break;

    case 's':
     sarg = va_arg(ap, const char *);        //get the argument and move on to the next
     outstream << sarg;
     break;
    case 't':
     outstream << "\t";
     break;

    default:
     outstream << *p;
     break;

  }
 }
 va_end(ap);

 g_pDebugListBox->AddString( outstream.str().c_str() );
 g_pDebugListBox->SetCurSel( g_pDebugListBox->GetCount()-1 );

// 여기에서 콘솔 모드면 아래 코드를 적용하면 될듯 하다.
 memset( pBuf, 0, sizeof(char) * 256 );
 strcpy( pBuf, outstream.str().c_str() );
 //p = pBuf;
 printf( pBuf );
}

Posted by gsi
:

Google
 
UML을 사용하다 보면 아직까지 익숙하지 않아서 화살표의 의미 자체가 조금 힘들게 받아 들여 진다.
아래의 이미지는 Iterator 패턴을 사용해서 화살표가 의미 하는 것을 적어 보았다.

사용자 삽입 이미지
Posted by gsi
:

Google
 

UML을 사용하다 보면 아직까지 익숙하지 않아서 화살표의 의미 자체가 조금 힘들게 받아 들여 진다.
아래의 이미지는 Iterator 패턴을 사용해서 화살표가 의미 하는 것을 적어 보았다.

사용자 삽입 이미지

Posted by gsi
:

프로그램 짜다가 저장한 이미지를 확인 하기 위해서 탐색기에서 이미지를 읽기 보다는
해당 알씨와 같은 이미지 프로그램에 인자로 해당 파일을 자동으로 열리게 하는게 좋을때가 있다.
아래와 같이 하면 해당 실행 파일을 실행할 수 있다.

char szProgramName[MAX_PATH]= {0, };
wsprintf (szProgramName, "C:\\Program Files\\ESTsoft\\ALSee\\alsee d:\\aaa.bmp");
STARTUPINFO si = {0,};
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
si.dwFlags = 0;

CreateProcess (NULL,
      szProgramName,
      NULL,
      NULL,
      FALSE,
      0,
      NULL,
      NULL,
      &si,
      &pi);
Posted by gsi
:

MFC 에서는 크게 발생하지 않았지만 Win32 쪽으로 코드를 옮기면서
몇가지 컴파일 오류들이 나왔다. 아래의 오류는 #inlcude <string>가 인클루드 되지 않아서
발생하는 문제였다.

#include <string>

c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139) : error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : 'const std::_Tree<_Traits> &'의 템플릿 인수를 'const std::string'에서 추론할 수 없습니다.
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xtree(1170) : 'std::operator`<'' 선언을 참조하십시오.
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139) : error C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : 'const std::_Tree<_Traits> &'의 템플릿 인수를 'const std::string'에서 추론할 수 없습니다.
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\xtree(1170) : 'std::operator`<'' 선언을 참조하십시오.
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139) : error C2784: 'bool std::operator <(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : 'const std::vector<_Ty,_Ax> &'의 템플릿 인수를 'const std::string'에서 추론할 수 없습니다.
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\vector(915) : 'std::operator`<'' 선언을 참조하십시오.
c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\functional(139) : error C2784: 'bool std::operator <(const std::vector<_Ty,_Alloc> &,const std::vector<_Ty,_Alloc> &)' : 'const std::vector<_Ty,_Ax> &'의 템플릿 인수를 'const std::string'에서 추론할 수 없습니다.
        c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\vector(915) : 'std::operator`<'' 선언을 참조하십시오.
Posted by gsi
:

스마트 포인터를 사용하고,
템플릿을 연동해서 여러가지 단위전략을 세울수 있다.

// CTest //
class CTest
{
public:
 CTest() {}
 ~CTest() }

public:
 int value;
};
typedef SmartPtr<CTest> CDeleteTestPtr;
typedef vector< CDeleteTestPtr > vObject;

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

// CTestArray //
template < template <class> class CreatePolicy>
class CTestArray
 : public CreatePolicy< CTest >
 , public vObject
{
public:
 CTestArray()
 {
  vObject::clear();
 }
 ~CTestArray() { }

 // Add라는 함수를 하나 제작해 봤다.
 // OpNewCreator를 사용해서 간접적으로 메모리를 생성한다.
 void Add(int idx)
 {
  CDeleteTestPtr ptr = OpNewCreator<CTest>().Crate();
  ptr->value = idx;
  vObject::push_back( ptr );
 }
};
typedef SmartPtr< CTestArray<OpNewCreator> > CTestArrayPtr;

///// 사용법
CTestArrayPtr ar;
for(int i = 0; i < 10; i++)
{
   ar->Add(i);
}

Posted by gsi
:

Smart Ptr

#ifndef SMARTPTR_H
#define SMARTPTR_H

template <class T> class SmartPtr;

// IRefCount 참조 횟수 관리를 위한 인터페이스
// 클래스들은 이것을 직접 구현해도 되고, 아니면
// 내부적으로 IRefCount를 구현하고 있는 SmartPtr을 사용해도 된다.

template <class T> class IRefCount {
    friend class SmartPtr<T>;
protected:
    virtual void AddRef() = 0;
    virtual void Release() = 0;
    virtual T* GetPtr() const = 0;
};

// IRefCountImpl
// IRefCount의 표준적인 구현
// 이것을 상속하기만 하면 참조 횟수 관리 기능이 생긴다.
// class CMyObject : public IrefCountImpl<CMyObjct> { ... };
// 주의: 개별 클래스가 IRefCount를 꼭 구현할 필요는 없지만,
// 직접 구현함으로써 메모리 단편화를 줄일 수도 있다.

template <class T> class IRefCountImpl
: public IRefCount<T>
{
private:
    int m_Count;

protected:
    virtual void AddRef() { m_Count++; }
    virtual void Release();
    {
        assert( m_Count>=0);
        m_Count--;
        if( m_Count<=0 )
        {
            Destroy();
        }
    }
    virtual T* GetPtr() const { return ( (T*)this ); }
    virtual void Destroy() { if(GetPtr()!=NULL) delete GetPtr(); }

    IRefCountImpl() { m_Count = 0; }
};

// SmartPtr

template <class T> class SmartPtr
{
private:
    IRefCount<T> *m_RefCount;
// RefCounter
// IRefCount를 직접 구현하지 않는 클래스를 위한 내부구현.
// SmartPtr은 이 내부 구현과 클래스 T의 IRefCount 구현중
// 적절한 것ㅇ르 자동적으로 선택한다.

    class RefCounter : public IRefCountImpl<T> {
    private:
         T *m_Ptr;
    protected:
         virtual T* GetPtr() const { return m_Ptr; }
         virtual void Destroy() { delete this; }

    public:
       RefCounter( T* ptr ) { m_Ptr = ptr; }
       virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
    };
//  T가 IRefCount를 구현하지 않았다면 이 메서드가 호출된다.
    void Assign( void *ptr )
    {
        if( ptr==NULL )
            Assign( (IRefCount<T> *)NULL );
        else
        {
            Assign( new RefCounter( static_cast<T*>(ptr) ) );
        }
    }

     // T가 IRefCount를 구현하고 있다면 Assign(void *ptr) 대신
// 이 메서드가 호출된다.
// 이를 통해서 메모리 사용이 좀더 최적화된다.
    void Assign( IRefCount<T> *refcount )
    {
        if( refcount != NULL )
             refcount->AddRef();
        IRefCount<T> *oldref = m_RefCount;
        m_RefCount = refcount;
        if( oldref!=NULL )
             oldref->Release();
    }
public:

    SmartPtr() { m_RefCount = NULL; }
    SmartPtr( T *ptr ) { m_RefCount = NULL; Assign(ptr); }
    SmartPtr(const SmartPtr &sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
    virtual ~SmartPtr() { Assign( (IRefCount<T> *)NULL); }

    T* GetPtr() const { return (m_RefCount = NULL ) ? NULL : m_RefCount->GetPtr(); }

    // 배정 연산자들
    SmartPtr& operator = (const SmartPtr &sp) { Assign(sp.m_RefCount); return *this; }
    SmartPtr& operator = (T* ptr) { Assign(ptr); return *this; }

    // T접근 및 const 변환
    T* operator -> () { assert(GetPtr() != NULL); return GetPtr(); }
    operator T* () const { return GetPtr(); }

    // 기타 편의성 연산자들
    bool operator ! () { return GetPtr() == NULL; }
    bool operator == (const SmartPtr &sp) { return GetPtr() == sp.GetPtr(); }
    bool operator != (const SmartPtr &sp) { return GetPtr() != sp.GetPtr(); }
};

#endif

다음은 템플릿 사용 예
SmartPtr.cpp

#include "stdafx.h"
#include "assert.h"
#include "smartptr.h"

class CMyObject
{
   char *name;
public:
   CMyObject(char *aname) { name = aname; printf( "create %s\n", name ); }
   virtual ~CMyObject() { printf("delete %s\n", name ); }
   void print() { printf("print %s\n",name ); }
};

SmartPtr<CMyObject> f1( char *name )
{
    return SmartPtr<CMyObject>(new CMyObject(name));
}

void f2( CMyObject *o )
{
    printf( " (print from a function) ");
    o->print();
}

int main( void )
{
    SmartPtr<CMyObject> ptr1(new CMyObject("1")); // 객체 1을 생성
    SmartPtr<CMyObject> ptr2 = new CMyObject("2"); // 객체 2을 생성

    ptr1 = ptr2; //객체 1을 파괴
    ptr2 = f1("3"); // 반환값으로 쓰이는 경우
    ptr2 = NULL; // 객체 3을 파괴
    f2(ptr1);

    // 잘못된 용례
    //  CMyObject o1;
    // ptr1 = &o1; // o1은 스택에 있으므로 이렇게 하면 안된다.
   
    // CMyObject *o2 = new CMyObject;
    // ptr1 = o2;
    // ptr2 = o2; // CMyObject가 IRefCount를 구현하지 않는 한 이렇게 하면 안된다.
    //     대신 ptr1 = ptr2를 사용할 것, 그것이 항상 안전하다.

    // int에 대해서도 SmartPtr을 사용할수 있다.
    SmartPtr<int> a(new int);
    SmartPtr<int> b(new int);

    *a = 5;
    *b = 6;

    // 명시적으로 파괴하지 않아도 메모리가 새지 않는다.
    return 0;
}

(펌) : http://blog.naver.com/twofree?Redirect=Log&logNo=21484155

Posted by gsi
:

단위 전략 부분의 디자인 패턴 내용을 보고 있다.

template 을 사용해서 다중 상속과 비슷한 구조를 취하기도 하고 메모리 생성 부분을 struct, class 형태로 따로 빼서 관리도 되는거 같다.

예제 1 :

class Ca
{
public:
 Ca() { value = 100; }
 virtual ~Ca() {}

 int value;
protected:
private:
};

template< class T>
class Cb
{
public:
 Cb() {}
 virtual ~Cb() {}

 T b;
protected:
private:
};

template< class T>
class Cc
{
public:
 Cc() {}
 virtual ~Cc() {}

 T c;
protected:
private:
};

template
<
 class T,
 template <class> class CheckingPolicy,
 template <class> class ThreadingModel
>
class SmartPtr
{
public:
 SmartPtr() {}
 ~SmartPtr() {}

public:
 T a;
 CheckingPolicy<T> b;
 ThreadingModel<T> c;
};

typedef SmartPtr<Ca, Cb, Cc> WidgetPtr;

위의 내용에서 보면 typedef를 사용해서 WidgetPtr을 하나 만들고 있다.
여기에 들어가는 내용은 Ca, Cb, Cc 가 있으며,
Cb, CC는 Ca를 포함할 수 있기 때문에 template로 선언되어 있는게 조건인듯 하다.

위와 같이 선언한 후에 아래와 같이 선언해서 사용하게 된다.

TestPtr< OpNewCreator > b;

이렇게 되면 b의 내용을 보면 SmartPtr의 클래스 내부에 b, c가 존재 하는데
이것은 T라는 템플릿 즉, Ca를 가지게 되며, 다른 동작들을 관리할 수 있을거 같다.

예제 2 :

class CTest
{
public:
 CTest() { value = 20; }
 ~CTest() {}

public:
 int value;
};

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

template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
{
public:
 TestPtr()
 {
  ptr = CreationPolicy<CTest>().Create();
 }
 ~TestPtr()
 {
 }

public:
 CTest* ptr;
};

OpNewCreator 라는 struct를 사용하면서 new를 처리해 준다.
이 곳에서 몇개의 다른 처리를 해서 넘겨 주는 형태를 취해도 될것 같다.

상속 형태로 해서 아래와 같은 코드로 작성 하면,
template < template <class T> class CreationPolicy>
class TestPtr : public CreationPolicy<CTest>
...
이렇게 하고 나서

ptr = CreationPolicy<CTest>().Create();
이런 식으로 생성할 수 있다. 이 코드 참 멋진듯 하다. ^^

생성해서 처리 하는 방법은 아래와 같습니다.

 TestPtr< OpNewCreator > b;
 b.ptr->value = 30;
 printf("%d\n", b.ptr->value);
 TestPtr< OpNewCreator > c;
 b.ptr->value = 50;
 printf("%d\n", b.ptr->value);

아뭍턴.. 템플릿을 구현하는 방법이 복잡하긴 하지만,
제대로 사용하면 정말로 많은 기능을 구사할 수 있다.
Posted by gsi
:

객체 지향 설계에서 기존의 것과는 독립된 새로운 것을 추가, 확장시키기 위한 가장 좋은 방법 중 하나가 클래스 상속(InHeritance)을 이용하는 것이다.

객체지향 설게에서 클래스 상속은 크게 두가지 목적을 가지는데,

하나는 상위 클래스가 여러 하위 클래스들의 공통된 데이터를 추출해서 관리하도록 만드는 것이고,
다른 하나는 상위 클래스는 전반적인 자료형을 대표 하면서 외부에 공통된 인터페이스를 제공하고, 하위 클래스들은 각기 다른 구현 내용을 가지도록 만들어 주기 위한 것이다.
Posted by gsi
:

State Pattern

C++ 2008. 1. 22. 09:21 |

State Pattern

사용자 삽입 이미지
< State 패턴예>


GamePlayer 클래스와 GameLevel 및 그 하위 클래스들은 모두 동일한 인터페이스를 가지고 있는데, 이는 GamePlayer 객체에 각기 다른 유형의 공격 요청이 주어졌을 때 이에 대한 처리를 GameLevel 및 그 하위 클래스에게 위임시키기 위한 것이다.
이때 GamePlayer 객체가 공격 요청을 위임시키기 위한 방법으로는 내부적으로 관리하고 있는 GameLevel 포인터 객체를 통해 다형성(Polymorphism)을 적용시키는 것이다.

추가된 상태를 포함해서 객체의 상태 변화 시 기존 소스코드 변경없이 행위 수행 변경이 가능하도록 객체 상태 정보를 클래스 상속 구조로 정의해서 사용하는 방식을 State 패턴이라고 한다.

Posted by gsi
:

Observer Pattern - Simple

C++ 2008. 1. 21. 12:25 |


Observer Pattern을 공부중..

사용자 삽입 이미지

<Observer 패턴예>


데이터와 뷰가 분리 되어 있을때 하나의 데이터를 두개 이상의 뷰에 의존적일 경우에
이 패턴을 사용하면 되는거 같아요.
즉, 데이터를 두개의 뷰에 업데이트가 가능하며, 하나의 뷰에서 데이터가 수정된 후에
다른 뷰에도 업데이트가 가능하게 됩니다.

Posted by gsi
:

#include <iostream>

 

using namespace std;

 

typedef void(*F)(int);

 

class QSpinBox

{

       int data;

      F handler;   // call back 함수 이게 포인트. 값이 변경되면 이 함수를 통해서 콜백을 한다.

public:

       QSPinBox(F f = 0 ) : handler(f) { }

       void SetValue(int n)

       {

             data = n;     // data가 변경되었다

             valueChanged(data);

       }

       void up() { ++data; valueChanged(data);   }

       void Down() { --data; valueChanged(data); }

 

private:

       // Spin은 내부 상태가 바뀔때마다 valueChanged가 호출되는데 여기서 외부로 알려지게 된다 - Signal 이라고 부른다.

       void valueChanged(int n)

       { // 여기서 callback handler를 관리하자

             if(handler != 0)

                    handler(n);

       }

 

 

};

 

int main()

{

       QSpinBox s;

       s.SetValue(100);

       s.Up();

}

 

// SpinBox 의 상태가 변경되면 외부에 알려준다 -> callback


(펌) - http://blog.naver.com/arcyze?Redirect=Log&logNo=60041494408

Posted by gsi
: