블로그는 나의 힘!
[ Programing ]/C++2010. 2. 18. 13:05
C++ 에서는 클래스 안의 함수(Function)라고 말하지만, 
Java의 같은 경우 클래스 외 쓰는 것을 말 그대로 함수라고 말하고 클래스 안에 쓰는 것을 메소드(Method)라고 구분한다.

함수도 마찬가지지만,
특히 클래스 내부에서 사용하는 멤버 함수는 그 구분을 명확히 하기 위해 이름 앞에 동사( 행동 )를 정확하게 기입하고 그 이름에 맞는 동작만 작성하는게 객체지향의 미덕이다.
( 멤버 변수명사( 형태 )로 시작한다. )

여기서 간단히 프로그래머가 암묵적 공통된 방식으로 사용하는 그 메소드 & 함수의 이름에 대해서 정리해 보고자 한다.



※ 추가 참조 설명
: 함수의 동사와 그 이름에 맞게 동작만 작성하는 것이 좋다. 
  예외처리 까지는 좋으나, 괘니 쓸데 없이 추가 기능을 넣는다고 넣어주면 당장은 쓸모가 있을지 모르겠으나, 
  추후 유지보수시 반드시 문제가 생기며 수정시 고생하게 된다. 
  만약, 추가 기능이 필요하다면 그 추가기능 함수를 다시 따로 만들어서 동작할 수 있도록 모듈화를 하자.
  오히려 이렇게 만들면 모듈화 보너스는 물론이거니와 유지 보수에도 좀더 효율적이고 쉽게 관리 된다.

ex:
public:
   long int SetIndex( long int index )
   {
        // long int m_nIndex 라는 멤버 변수가 있을 경우.       
        // std::vector<long int> m_vecIndex 라는 멤버 변수가 있을 경우.
        m_nIndex = index;       
        m_vecIndex.push_back( index );

        // 만약 추가적으로 인덱스를 효율적으로 관리 하기 위해
        // 인덱스 삽입시 m_vecIndex 라는 멤버 변수를 바로 정렬하고 싶다면,
        // 여기서는 추가로 만들지 말고 함수 이름 그대로 SetIndex기능만 하도록 하고
        // sort() 함수를 따로 만들어 모듈화 시킨다. 만약 밖에서 사용이 아닌 내부 사용시
        // protected 나 private에서 만들어 준다.
        SetVectorIndexSort();

        return m_nIndex;
   }

// 굳이 외부 사용 목적이 아니라면, 은닉화 하자.   
pretected:
   // 추가로 만들기 위한 함수를 SetIndex에서 만들지 말고, 이렇게 따로 만들어 모듈화 한다.
   bool SetVectorIndexSort()
   {
        sort( m_vecIndex.begin(), m_vecIndex.end(), SortIndex );

        return true;
   }

   bool SortIndex( long int index1, long int index2 ) { return ( index1 < index2 ); }




=================================== 데이터 반환 & 변경 함수 =====================================
: 굳이 이렇게 만들지 말고 변수를 public 으로 해도 상관 없다고 말하는 사람이 있다면....
  객체지향 oop 개념을 다시 숙지 하길 바란다. 
  객체지향은 모듈화, 다양성, 관리의 편리 등 여러가지가 있으나 핵심은 뭐니 뭐니해도 캡슐화 정보의 은닉, 은폐가 핵심이다.
  
  정보를 은닉하여, 
  기타 밖에서 다른 유저나 추후 유지 보수시 자칫 잘못 데이터를 건들어 심각한 오류를 방지하는 것이 최고 장점이다.
  그래서 필요시 사용하라고 이렇게 함수들을 제공해 제한을 걸어 주는것이 최고의 방법인 셈이다.
  이런 제공 함수도 만들때 필요할 것인지, 추후 유지 보수도 생각해 어느 정도 제공할 것인지 생각하고 만드는 것이 중요하다.


long int GetFunction();
- Get의 정의는 해당 데이터를 가져 오기 위한 함수. 
  여기서는 long int로 데이터를 받아오는 함수이다.
- 보통 간단히 데이터만 반환하는 함수라 크게 조건문을 넣는 일이 드물어 
   inline으로 작성해 속도 개선 및 간편화를 시키는 함수 중 하나.
  ( ex : inline long int GetFunction(); )

long int SetFunction( long int data );
- Set의 정의는 해당 데이터를 변경 하기 위한 함수. 
  여기서는 인자 nData 변수로 데이터를 변경하는 함수이다.
  반환값은 굳이 필요 없다면 void로 해도 상관 없다.

long int IsFunction();
- Is의 정의는 해당 변수나 오브젝트를 평가하는 함수.
  Get과는 다른 것은 Get은 해당 객체의 클래스 내부 멤버 변수의 값이나 포인터를 가져오기 위한 의미라면,
  Is는 그 함수에 맞는 처리를 계산하여 평가를 반환 하는 함수.

  쉽게 말해서 내부에선 사용하지 않고 Is로 정의된 함수가 끝나면 소각되어 버리는 ( 어찌 보면 지역 변수 ) 데이터 값이나, 
  그 반환값이 필요한 경우 반환하기 위해 존재하는 함수이다.
  보통은 반환 값이 bool로 그 평가가 true, false 인지만 알기 위해 주로 쓰인다. 
  사용자의 입맛에 따라서 int로 그에 해당한 값을 반환하는 용도도 괜찮은 편.


long int TakeFunction();
- Take의 정의는 해당 데이터 값이 이동 하는 함수.
  구조상으로 말하자면 데이터를 반환하면 해당 멤버 변수는 초기화 되어 버린다.
  보통 데이터 값이 복사나 참조가 아닌 이동 시 사용 하는 함수이다.
  ( 근데 실제론 사용해 본적이 드물다. )



===================================== 동적 처리 함수 =======================================
: 동적으로 실시간 처리를 위해 만드는 함수이다.
  계속 프레임마다 체크를 하여 데이터 상태나, 출력을 위해 주로 사용 하는 함수이다.


bool FrameMove( double passTime );
- FrameMove의 정의는 동적으로 실시간 처리해야 하는 함수. 
  보통 실시간으로 어떤 행동을 하는지, 변경된 값이 무엇인지 체크하는 함수이다. 

  객체지향의 클래스 구조에선 약방의 감초처럼 80%정도는 꼭 있는 녀석.
  void로 작성해도 상관 없으나, bool 함수로 FameMove가 동작이 잘되는지 않되는지 체크 하는 것도 괜찮은 팁이다.

bool Render( double passTime );
- Render의 정의는 동적으로 실시간 처리해야 하는 함수. 
  FrameMove와 마찬가지이나 이녀석은 실시간 출력( Display )이 목적인 함수이다.

  마찬가지로, 객체지향의 클래스 구조에선 약방의 감초처럼 80%정도는 꼭 있는 녀석.
  void로 작성해도 상관 없으나, bool 함수로 Render가 동작이 잘되는지 않되는지 체크 하는 것도 괜찮은 팁이다.

  결론적으론 FrameMove와 동작이 같으나, 왜 따로 2가지를 만들어 관리하냐면, 
  동적 실시간 처리 함수는 그만큼 핵심이며 관리하기 편하기 위해서이다. 
  때론 내용이 방대할 수 있어서, 데이터 처리 부분과 출력 처리 부분이 따로 있어 서로 간섭이 없도록 하여,
  추후 유지 보수시 좀더 효과적으로 관리 하기 위한 것이다.
  
bool Process( double passTime );
- Process의 정의는 동적으로 실시간 처리해야 하는 함수. 
  위 FrameMove와 Render 마찬가지이나 이녀석은 총괄적인 함수이다.
  보통 최상위 객체( Main급 )에서 다른 생성된 객체들의 동적 처리 함수를 위해 사용한다.

  void로 작성해도 상관 없으나, bool 함수로 Process가 동작이 잘되는지 않되는지 체크 하는 것도 괜찮은 팁이다.

  ex : 
  bool Process( double passTime )
  {
       // class Game 라는 cGame 동적 객체를 만들었을 경우.
       cGame->FrameMove( passTime );
       cGame->Render( passTime );

       return true;
  }



================================== 생성, 해제 & 초기화 함수 =====================================
: 보통 일반 사용자들은 그냥 초기화시 생성자에서 초기화 하고, 소멸자에서 객체나, 동적변수를 해제 시킨다.
  하지만 좀더 효율적으로 관리 하기 위해선 이것도 함수로 묶어 두는 것이 좋다.

  생성자, 소멸자에서만 초기화, 생성, 해제 하는 것이 아닌 언제든 사용자 입맛에 맞게 
  초기화, 생성, 해제를 할 수 있게 만드는 것이 중요하다. 

  이것으로 예외 처리도 가능하고, 언제든 사용자 입맛에 맞게 초기화 생성, 해제를 관리해 줄 수 있기 때문이다.


bool Initialize();
- 멤버 변수(멤버 객체) 중 동적 멤버 변수를 생성하기 위해 사용하는 함수.
- 생성자에서 사용은 물론, 사용자가 언제든 생성 호출 할 수 있게 따로 이렇게 함수로 만들어 둔다.
- 생성된 멤버변수를 다시 생성한다면 메모리 누수 문제가 있을 수 있으니, 
  Release()를 먼저 호출해 동적 멤버 변수가 생성이 되어 있다면(NULL이 아니라면)
  해제하게 만들어 생성할 수 있도록 만들어 놓자.

bool Release();
- 멤버 변수(멤버 객체) 중 동적 멤버 변수를 해제하기 위해 사용하는 함수.
- 소멸자에서 사용은 물론, 사용자가 언제든 해제 호출 할 수 있게 따로 이렇게 함수로 만들어 둔다.
  SAFE_DELETE() 매크로를 이용하여 NULL이 아닐 경우, 해제하는 방식으로 만들자.
  ( 아래 팁 참조 )

bool Clear();
- 멤버 변수를 초기화 하기 위해 사용하는 함수.
- 생성자에서 초기화는 물론, 사용자가 언제든 초기화 할 수 있게 따로 이렇게 함수로 만들어 둔다.



=============================================================================================

<<< 팁_1 >>>
: 생성자와 소멸자에서는 이렇게 사용하면 효율적이다.

  #define SAFE_DELETE(p) { if(p){ delete (p); (p)=NULL; } }

  class Object 
  {
       long int m_nIndex;
       long int m_nKey;

       Game*    m_cGame;

  public:
       Object( const Object& rhsObejct );
       Object()
       {    
            m_cGame = NULL;
 
            Initialize();
            Clear();
       }
       
       ~Object()
       {     
            Release();
       }

       bool Initialize()
       {    
            // 생성하기 전 해제를 호출 하는 이유는
            // 생성되어 있는 동적 변수(동적 객체)를 다시 생성할 경우 메모리 누수가 일어 난다.
            // 그것을 방지하기 위해 미리 생성된 동적 변수를 해지 한 다음 생성하기 위한 것이다.
            // 일종의 예외 처리이다. 생성되지 않았다면 ( NULL이었다면 ) Release에서 그냥 통과한다.
            Release();

            m_cGame = new Game;

            return true;
       }

       bool Release()
       {    
            SAFE_DELETE( m_cGame );

            return true;
       }

       bool Clear()
       {    
            m_nIndex = 0;
            m_nKey   = 0;

            return true;
       }
  }


-----------------------------------------------------------------------------------

※ <<< 팁_2 >>>
: 생성자와 소멸자에서는 이렇게 사용하면 효율적이다.

  #define SAFE_DELETE(p) { if(p){ delete (p); (p)=NULL; } }
  #define SAFE_DELETE_ARRAY(p) { if(p){ delete[] (p); (p)=NULL; } }

  #define NUMBER_MAX      (10)

  class Object 
  {
       bool         m_bCreate;    // 생성 & 해제 & 초기화 관련에 사용하는 멤버 변수.
       long int     m_nIndex;
       long int     m_nKey;

       long int*   m_pnNumber;
       Game*     m_cGame;

  public:
       Object( const Object& rhsObejct );
       Object()
       {    
            m_cGame      = NULL;
            m_pnNumber = NULL;
            m_bCreate  = false;
 
            Initialize();
            Clear();
       }
       
       ~Object()
       {     
            Release();
       }

       bool Initialize()
       {    
            // 이렇게 중복 생성을 막아 메모리 누수를 해결하며,
            // 반환 값을 false을 되돌려 생성이 안되었다는 것을 알려 준다.

            if( m_bCreate ) return false; 
    
            m_bCreate   = true;       // 생성이 되었다는 것을 선언하기 위해 true 값으로 변경 한다.

            m_cGame       = new Game;
            m_pnNumber   = new long int[NUMBER_MAX];

            return true;
       }

       bool Release()
       {    
            // 동적 멤버 변수를 해제시키니,
            // 생성이 해지&생성 되지 않았다는 것을 선언 하기 위해 false 값으로 변경 한다.

            m_bCreate    = false;

            SAFE_DELETE_ARRAY( m_pnNumber );
            SAFE_DELETE( m_cGame );

            return true;
       }

       bool Clear()
       {    
            m_nIndex      = 0;
            m_nKey        = 0;

            // 동적 멤버 변수가 생성되지 않았다면 이렇게 조건을 달아 필터한다.
            if( !m_bCreate ) return false;

            // 동적 멤버 변수가 생성이 되었다면 동적 멤버 변수를 초기화 한다.
            memset( m_pnNumber, 0, sizeof( long int ) *NUMBER_MAX );

            return true;
       }
  }



-----------------------------------------------------------------------------------

※ <<< 팁_3 >>>
: 생성자와 소멸자에서는 이렇게 사용하면 효율적이다.

  #define SAFE_DELETE(p) { if(p){ delete (p); (p)=NULL; } }
  #define SAFE_DELETE_ARRAY(p) { if(p){ delete[] (p); (p)=NULL; } }

  #define NUMBER_MAX      (10)

  class Object 
  {
       long int     m_nIndex;
       long int     m_nKey;

       long int*   m_pnNumber;
       Game*     m_cGame;

  public:
       Object( const Object& rhsObejct );
       Object()
       {    
            m_cGame      = NULL;
            m_pnNumber = NULL;
 
            Initialize();
            Clear();
       }
       
       ~Object()
       {     
            Release();
       }

       bool Initialize()
       {    
            // 생성이 되었는지 확인 후 NULL 이라면 생성.
            if( m_cGame )        m_cGame       = new Game;
            if( m_pnNumber )   m_pnNumber   = new long int[NUMBER_MAX];

            return true;
       }

       bool Release()
       {    
            SAFE_DELETE_ARRAY( m_pnNumber );
            SAFE_DELETE( m_cGame );

            return true;
       }

       bool Clear()
       {    
            m_nIndex      = 0;
            m_nKey        = 0;

            // 생성 되었다면 초기화.
            if( m_pnNumber )   memset( m_pnNumber, 0, sizeof( long int ) *NUMBER_MAX );

            return true;
       }
  }

Posted by Mister_Q