home > working > C/C++ > Source, Tip

 


Name  
   조규남 
Subject  
   [강좌] How to use C++ in MFC No.1 Operator Overload

1차시 강좌에 들어 가며

C++을 처음 배우면서 이런 의문을 누구든지 가졌을 것이다. "이 문법을 왜 배워야 하지? 이런 것들이 쓰이기는
하나?" 라고 말이다.필자 자신도 C++을 처음 배우면서 그런 의문을 많이 가졌었다. 특히나 Virtual 함수를 왜
배워야 하는지는 정말이지 알 수 없었다. -_-; 그런 의문을 가지고 배우는 문법이 머리에 남을 리 없었다.
더군다나 강사는 Virtual 함수를 자제만 가르쳐 줬지 어디에 어떻게 쓰이는지를 알려주지 않았다. 이런 의문들은
나중에 MFC로 실제 Project를 수행하면서 조금씩 풀리게 되었다. 아 이런 문법이 이래서 필요하구나 라고 말이다.
나와 같이 이런 반복되는 학습을 다른 사람들은 피할 수 있도록 그런 문법이 MFC에 어떻게 적용되고 왜 필요한
문법인지를 설명해 나가도록 하겠다.

그럼 지금부터 1차시 강좌를 시작하겠다.

Operator Overload는 우리 말로 연산자 중복 정의이다. 글자 그대로 연산자를 내가 중복해서 정의를 하는 것이다.
이 개념을 이해하기 위해서는 반듯이 Function Overloading을 이해하여야만 한다.

Operator Overload는 Class의 Member Method나 Friend Method로서 존재 한다. 즉 Class안에서 정의 된다는 말이다.
쉽게 이야기 하면 우리가 만든 클래스를 마치 기본 데이터 형인 int 처럼 +, -, *, / 연산을 수행할 수 있다는 말이다.
사칙 연산 이외에도 Type casting, [] 등과 같은 연산자들도 Overload 할 수 있다. 

하지만 많은 사람이 의문을 가질 것이다. 함수로 만들어도 될 저런 동작을 왜 구지 어렵게 Operator Overload를
사용해서 재정의 해야 하는지를 말이다. 나 역시 동의 한다. -_-; 사실 개념을 이해하기는 쉬워도 활용하는 것은
그리 쉽지 않다.필자 역시 내가 만든 Class에 Operator Overload를 사용해 본 적이 없다 -_-;;;; 부끄러울 따름이다.

하지만 이 강좌의 제목은 How to use C++ in MFC 이다. 그래서 MFC에서 이놈의 Operator Overload의 예제를 생각해
봤다. 대상은 두 번 생각할 것도 없이 "CString" Class였다. 의아해 하는 사람도 있을 테고, 맞다라구 생각하는 사람도
있을 것이다. 우리는 MFC를 사용할 때 CString Class를 굉장히 많이 사용한다. 예를 들어 보도록 하겠다.

    CString        strTemp;
    char            szTemp[1024];

    strTemp.Empty();
    strTemp = "workingC 강좌";
    strTemp += " : No 1. Opertor Overload";

    strcpy(szTemp, (LPCTSTR)strTemp);
    szTemp[4] = strTemp[5];

모두다 알고 있다시피 szTemp에는 "worknngC 강좌 : No 1. Opertor Overload" 라는 문자열이 저장되게 된다.
만약 반대한다면 C 공부를 다시 하기 바란다. -_-+. 위의 소스에서 Operator Overload로 재정의된 연산자가 몇
개일까? 정답은 4개이다. 강좌를 읽고 있는 모두가 100점이기를 바란다. 여러분의 예상대로 =, +=, LPCTSTR, []
모두가 Operator Overload로 재정의 된 연산자들이다. CString에 이런 연산자가 존재하기 때문에 우리는 strcat,
strcpy, strcmp 등의 함수를 복잡하게 사용하지 않고 마치 더하기 빼기 하는 것 같이 문자열을 재조합 할 수 있는
것이다. 이런 편리한 함수를 왜 안 사용 하지 않았냐구 묻는다면 대답할 것이다. 만들기는 귀찮다 -_-; Class에서
Operator Overload를 사용할 경우 Class자체의 메모리 문제를 신경써야 하기 때문에 여간 귀찮은 것이 아니다.
CString에서는 소멸자에서 메모리 해제를 하기 때문에 크게 신경 쓸 것이 없지만 Custom Class에서는 멤버도
많기 때문에 그리 녹녹한 작업은 아닐 것이다.하지만 이렇게 편리한 것이라면 조금 귀찮다구 하더라도 배워두면
뼈가 되고 살이 되지 않겠는가?

Operator Overload는 다음과 같이 이루어 진다. 

const CString& CString::operator+=(LPCTSTR lpsz)
{
    ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
    ConcatInPlace(SafeStrlen(lpsz), lpsz);
    return *this;
}

빨간색 부분은 리턴형이고(대부분 Class자신) 파란색 부분은 연산자의 종류, 녹색 부분은 연산자의 인자이다.
+= 은 Concat를 하는 함수이다. 구현부에서 ConcatInPlace 함수를 호출해서 Concat 작업을 수행한다. 
위에서도 언급했지만 인자로 들어오는 부분의 메모리 관리를 해주어야 한다. CString의 경우는 소멸자에서
메모리를 해제해주지만 Class자체에 메모리 할당이 많고 수동으로 해제해주는 Class라면 특히 주의 해야 한다.

Operator Overload를 쉽게 이해하는 방법은 Operator Overload라는 말을 잊어 버리고 operator라는 함수를
재정의한다고 생각하는 것이다. 위의 예제의 경우 operator+= 이라는 함수를 재정의 한다고 생각하면 쉽다.
실제로 Source에서

    strTemp += " : No 1. Opertor Overload";

이 부분을 

    strTemp = strTemp.operator+=(" : No 1. Opertor Overload");

이렇게 사용하여도 문제 없이 동작된다. X팔린 예기지만 처음에 CString을 char*로 변경할 때 이렇게 사용했었다.
본론으로 돌아와서 구지 어렵게 Operator Overload라 생각하지 말고 이름이 특이한 함수의 Overload라고 생각하면
훨씬 쉬워질 것이다. 

마지막으로 주의 할 점 두 가지!

- Operator Overload로 재정의 할 수 없는 연산자

? : (3항 연산자), * (포인터 Value 참조), . (dot 연산자-클래스 또는 구조체의 멤버 엑세스), :: (Scope Operator)
들이다. 이들 연산자들은 문법적으로 특별한 의미로 사용되는 연산자들이기 때문에 재정의를 했을 경우 문제가 발생할 수 도 있기 때문이다.

- friend 함수의 사용

다음 코드를 보자

#ifdef _UNICODE
// concatenate an ANSI character after converting it to TCHAR
    const CString& operator+=(char ch);
#endif
// concatenate a UNICODE character after converting it to TCHAR
    const CString& operator+=(LPCTSTR lpsz);

    friend CString AFXAPI operator+(const CString& string1,const CString& string2);
    friend CString AFXAPI operator+(const CString& string, TCHAR ch);
    friend CString AFXAPI operator+(TCHAR ch, const CString& string);
#ifdef _UNICODE
    friend CString AFXAPI operator+(const CString& string, char ch);
    friend CString AFXAPI operator+(char ch, const CString& string);
#endif
    friend CString AFXAPI operator+(const CString& string, LPCTSTR lpsz);
    friend CString AFXAPI operator+(LPCTSTR lpsz, const CString& string);

+ 연산자를 재정의 하면서 firend 함수를 사용하였다. 왜 일까? 각 연산자 재정의에 보면 인자로 CString이 들어
온다. 재정의 함수에서는 CString의 내부 함수를 호출해서 일련의 동작을 수행해야 한다. +의 경우 앞에
CString에서 ConcatInPlace을 호출할 것이다. 이때 문제가 발생하는데 CString Object에서 ConcatInPlace 함수를
호출해야 하는데 이 함수는 CString의 Protected 함수 이다. 때문에 외부에서 호출 할 수 있는 함수가 아니다.
코드가 CString에 존재한다고 하지만 Object로 들어온 인자는 해당 Object의 일부가 아니기 때문에 호출 할 수 없다.
따라서 Protected 함수를 호출해주기 위해서는 friend 함수이어야 한다. 물론 Public으로 선언하면 문제가 없겠지만
OPP 관점에서 본다면 문제가 발생할 수 있을 것이다. 이런 문제로 Object를 사용해야 하는 연산자 재정의는 friend로 선언해야 하는 것이다.


yonahtif :: None 2010/03/27  

Name Memo Password  
        


Prev
   C에서 C#까지 체계적으로 공부 할 수 있는 책 목록 [1]

조규남
Next
   오토마우스 오토 키보드 만들기 (허접강좌) ^^;;

이상수


Copyright 1999-2018 Zeroboard / skin by JiYoo / edit by Mystous