일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 나르왈프레오
- Google App Engine
- 삼성전자 소프트웨어멤버십 SSM
- 삼성
- 파이썬
- Python
- 물걸레자동세척로봇청소기
- 패턴 인식
- 멤버십
- 인공지능
- NarwalFreo
- Friendship
- SSM
- 빅데이터
- 구글 앱 엔진
- 신경회로망
- Bidirectional Associative Memory
- 삼성소프트웨어멤버십
- 갤럭시탭S8울트라
- 하이퍼바이저
- Neural Network
- 물걸레로봇청소기추천
- 고려대학교
- hopfield network
- 패턴인식
- 동아리
- 신경망
- 증강현실
- BAM
- 가상화
- Today
- Total
정보공간_1
[4기 신촌 백재현] C++ 증감 연산자(var++/++var)를 연산자 오버로딩 하기 본문
[4기 신촌 백재현] C++ 증감 연산자(var++/++var)를 연산자 오버로딩 하기
알 수 없는 사용자 2013. 11. 1. 03:45안녕하세요 신촌멤버십 22-1기 백재현입니다.
이번 글에서는 C++의 기본 문법인 '연산자 오버로딩' 사용에 있어서, 증감 연산자의 오버로딩에 대해 심도있게 알아보고자 합니다. 이 과정중 나오는 임시 객체, const 함수, 참조 리턴 등에 대해서도 간략하게 짚고 넘어갈 예정입니다. 글의 예시에서는 증가 연산자(++)를 사용하여 설명하도록 하겠습니다.
다들 아시다시피 증가 연산자에는 전위형(++var)과 후위형(var++)이 있습니다.
이해하기 쉽게, 해당 연산들은 C++에서 '함수'로써 동작한다고 생각하시면 좋습니다.
전위형 연산자 함수의 리턴값은 변수에 1을 더한 값이고, 후위형 연산자 함수의 리턴값은 변수 그대로의 값입니다.(변수 그대로를 리턴 한 이후에 값이 증가됩니다.)
이러한 처리는 어떻게 이루어 지는 것일까요? 연산자 오버로딩과 함께 알아봅시다.
우선 기본적인 증가 연산자의 사용을 확인해 보겠습니다.
결과는 당연히 11, 11이 나옵니다. ++n1을 통하여 11이 리턴 되었고 n1++을 통하여 11이 리턴되었기 때문입니다.
이제 우리는 증가 연산자를 오버로딩 하기 위해 Int32라는 클래스를 하나 만들것 입니다.
연산자 오버로딩의 방법은 쉽게 다음과 같이 생각 할 수 있습니다.
후위(var++) : 클래스명 operator++( int )
로 구성됩니다.
따라서 Int32 클래스를 다음과 같은 형태로 구성 할 수 있습니다.
크게 문제 없어 보이는 코드이며 다음과 같이 실행 했을 때 잘 돌아가는 것을 확인 할 수 있습니다.
결과값은 10, 12로, 예상 그대로 나왔습니다. 하지만 위의 코드는 다음과 같은 맹점이 있습니다.
바로 위의 코드가 무사히 컴파일이 된다는 점입니다.
기본적으로 후위 증감의 경우 연속해서 사용할 수 없습니다. 즉
같은 표현은 사용 할 수 없다는 말입니다.
그렇다면 이를 막기 위해선 어떻게 해야할까요? 함수 앞에 const를 써주는 방법을 사용하면 됩니다.
클래스 내부 함수 앞에 const를 쓰는 경우, 리턴한 값에 변화를 주는 것을 막습니다.
즉 const Int 32 operator++( int )에서 리턴하는 temp (*this의 복사 객체)의 값을 변경 할 수 없음을 의미합니다. (정확히는 temp의 임시객체의 값을 변경 할 수 없는 것인데 이는 복잡하므로 우선 넘어가도록 하겠습니다.)
n2++++의 수행 과정을 살펴보면, n2++이 먼저 수행되고, 리턴된 객체에 다시 ++ 함수를 수행하여 값을 변경하려 시도하는데, const를 걸어 줌으로써 뒷부분의 수행을 막을 수 있게 됩니다.
즉 n2++++의 수행 과정 중, 먼저 수행된 n2++의 리턴 타입이 const Int32이기 때문에 이후 ++을 바로 수행 할 수 없게 됩니다.
이렇게 하여 보완된 후위형 증가 연산자의 오버로딩은 다음과 같이 구성됩니다.
이와 같이 const를 붙임으로써 컴파일 단계에서 var++++ 형태의 구문 에러를 잡을 수 있습니다.
또 다른 문제는 전위 증가 연산에서도 발견 할 수 있습니다.
후위 증가 연산자와는 다르게 전위 증가 연산자는 위와 같이 두번 이상 연속으로 연산자 사용이 가능합니다. 위의 소스를 돌린 결과값은 예상하는 대로 12가 나옵니다.
그렇다면 위의 소스코드를 실행한 결과는 몇이 나올까요? 당연히 12가 나올까요?
아쉽게도 11이라는 결과가 나옵니다.
어째서 그런 결과가 나올까요? 이는 바로 '임시 객체' 때문입니다.
임시객체는 다음과 같은 상황에서 생성됩니다.
1. 함수 호출 시 암시적 타입 변환을 할 때
2. 함수가 객체를 반환 할 때
현재 상황은 이들 중 2번에 해당합니다.
위에서 해당 후위 증가 연산 함수를 설명함에 있어 임시 객체에 대해 언급했었습니다.
해당 함수에서 일어나는 일을 Line by Line으로 살펴보도록 하겠씁니다.
1) Int32 temp = *this;
Int32 자료형의 temp를 선언하고, *this를 대입합니다. 여기서 *this의 복사 생성자가 호출 됩니다. 즉 temp는 *this와 완전히 동일한 값을 가진 쌍둥이지만 같은 메모리 영역에 할당되진 않습니다.
2) ++val;
val의 값을 증가 시킵니다.
3) return temp;
temp를 리턴합니다. 여기서 중요한 것이 있습니다. 이때 반환하는 것 역시 temp 객체 자체가 아닌 복사 생성자를 통해 생성된 '임시 객체'를 리턴하게 됩니다. 만약 임시 객체가 아닌 temp 객체 그대로를 리턴한다면, 해당 함수의 스코프 끝에서 지역 변수인 temp는 사라져 버리게 될 것입니다. 따라서 이 함수를 호출한 곳에서는 반환된 데이터를 사용 할 수 없게 됩니다. 하지만 복사 생성자를 통해 생성된 '임시 객체'를 반환 하기 때문에 외부에서 호출한 함수에서 이를 사용 할 수 있는 것 입니다. 즉 해당 라인에서 하는 일은 단순히 'temp를 리턴합니다' 라기 보다는 'temp의 임시 객체를 리턴합니다.'가 정확한 표현이라 볼 수 있겠습니다.
이제 다시 오버로딩한 전위 증가 연산자를 살펴보겠습니다.
++++n2를 실행하면 처음 ++n2가 실행 될 것입니다. 해당 함수의 반환 값은 *this가 아닌 *this의 임시 객체입니다. n2안의 val 값은 증가 되더라도 리턴된 결과 값은 본인이 아닌 쌍둥이 형제라는 의미입니다.
이제 다시 앞쪽의 ++이 수행 될 것이고, 이 때 중요한 것이 'n2 본인'에 ++을 수행 하는 것이 아닌 위에서 리턴한 '쌍둥이 형제'에 ++을 수행한다는 것입니다. 수행한 결과 쌍둥이 형제의 val 값은 12가 되겠지요. 하지만 정작 중요한 n2 본인의 값은 11 그대로 입니다.
이를 해결하기 위해서 어떻게 해야할까요? 바로 참조 리턴을 사용하면 됩니다.
이처럼 타입 뒤에 &(reference)를 붙이게 되는 경우 이를 '참조 리턴'이라 합니다.
다들 call by value나 call by reference를 알고 계실 겁니다. call by reference의 경우 인자 값에 &를 붙여서 단순히 변수의 값을 받는 것이 아닌, 변수의 주소 그대로를 참조하여 호출할 때 사용합니다.
참조 리턴 역시, 데이터의 복사 값을 리턴 하는 것이 아닌, '그대로의 데이터'를 리턴 하도록 합니다.
즉 Int32& 타입에서 *this를 리턴 하게 되는 경우, *this의 임시 객체를 리턴 하는 것이 아닌 *this 자체를 리턴한다는 말입니다.
이렇게 할 경우 ++++n의 수행이 올바르게 이루어 지게 됩니다.
처음 ++n을 통해 리턴받은 값이 쌍둥이 형제가 아닌 n2 본인이며, 여기에 다시 ++을 할 경우 정상적으로 수행되어 원하는 결과가 나오게 됩니다.
위에서 설명한 것을 토대로 완성한 Int32의 전신은 다음과 같습니다.
완성 된것 같은 위 클래스에서 바꿔 줄 수 있는 부분이 한 부분 더 있습니다. 바로 후위형 증가 연산자의 ++val 부분입니다. 이를 ++(*this);로 바꿔주는 경우, 후에 코드를 유지하기가 더욱 쉬워집니다.
만약 증가 연산자의 수행 결과가 1이 아닌 2를 더한 값을 내놔야 한다면, 기존의 코드에서는 전위형과 후위형 두군데에서 소스코드를 수정해 줘야 하지만, 기존 코드를 재사용한 ++(*this)의 경우는 전위형에서만 변경해 주면 되기 때문입니다.(단순히 코드가 동작하도록만 짜는 것 보다는 유지보수가 용이하게 코드를 짜는 것이 매우 중요합니다!!)
대망의 결과물을 보도록 하겠습니다.
지금까지 C++ 증감 연산자의 연산자 오버로딩을 알아 보았습니다. 중간에 const 함수, 임시 객체, 참조 리턴 등에 대해서도 익히셨으리라 생각됩니다.
해당 글을 읽으시면서 이해가 안되거나 더 알고 싶은 점이 있으시다면 언제든지 코멘트 남겨주시기 바랍니다. 감사합니다.
'IT 놀이터 > Elite Member Tech & Talk' 카테고리의 다른 글
[4기 신촌 백재현] C++ algorithm 헤더의 sort()를 사용하여 struct를 정렬해보자. (0) | 2013.11.04 |
---|---|
[4기 신촌 김시재] Scrnsave 라이브러리를 이용한 화면보호기 #1 (0) | 2013.11.02 |
[4기 강남 박인수] 모바일 앱 크래쉬 분석 서비스 BugSense (0) | 2013.10.31 |
[4기 강남 박인수] HotSwap기능이 있는 JRebel 사용법 #2 (0) | 2013.10.31 |
[4기 강남 박인수] HotSwap기능이 있는 JRebel 사용법 #1 (0) | 2013.10.31 |