다음과 같은 코드가 있습니다. 어떤 값이 출력될까요?


[코드 1]
int main()
{
  int a = 0;
  a = ++a + ++a;
  cout << a << endl;
}

[실행 1]
4


얼핏 생각하면 결과는 3이 나와야 하는데, 실제로는 4가 나오는 것을 확인할 수 있습니다.




위의 코드를 약간 풀어서 설명을 해 보겠습니다. 순서는 (B) > (D) > (C) > (A) 순으로 실행이 된다고 볼 수 있습니다.


a =    // (A)                       (C)결과저장
  ++a  // (B) a증가
  +    // (C)           (A)와(B)더함
  ++a; // (D)      a증가


결과가 4가 나오는 이유는 (B)+(D)의 수행 과정에서 "1+2"가 아닌 "2+2"로 연산을 하기때문에 발생하는 현상입니다(서로 다른 객체간의 덧셈이 이루어 지는 게 아니라, 똑같은 객체가 더해져 버림)이는 C/C++ 언어의 ambiguity로 볼 수 있으며, 이렇게 실행 결과를 예측하기 힘들게 코딩을 하는 것은 그리 좋은 방법은 아니라고 볼 수 있습니다.




아무튼, 분석을 좀 해 봤습니다. C++로 클래스를 만들다 보면 가끔은 operator를 overloading해서 클래스를 설계하기도 하는데요, 위의 코드를 실행할 수 있도록 다음과 같이 operator를 overloading해 봤습니다( 참조 : http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B ).


[코드 2]
class VInt
{
protected:
  int _i;

public:
  VInt()                                 { _i = 0;                            } // A a      : Default constructor
  VInt(const VInt& b)                    { _i = b._i;                         } // A a(b)   : Copy constructor
  VInt(const int i)                      { _i = i;                            } // A a(i)   : Conversion constructor
  ~VInt()                                {                                    } // delete a : Destrutor

  VInt& operator = (const VInt& b)       { _i = b._i;           return *this; } // a = b    : Basic assignment
  VInt  operator + (const VInt& b) const { VInt res(_i + b._i); return res;   } // a + b    : Addition
  VInt& operator ++()                    { _i++;                return *this; } // ++a      : Prefix increment
VInt operator ++(int) { VInt res(_i); _i++; return res; } // a++ : Suffix increment operator int() const { return _i; } // (type)a : Cast };




[코드 1]에서 int를 VInt로 수정한 후 테스트를 해 보았습니다. 결과는 [실행 1]과 동일합니다.


[코드 3]


int main()

{
  VInt a = 0;
  a = ++a + ++a;
  cout << a << endl;
}

[실행 3]
4




여기에서 눈여겨 봐야 할 것은 [코드 2]의 Prefix ++ operator의 반환값 type입니다. 일반적으로 Prefix ++ operator는 reference를 반환하고, Suffix ++ operator는 object를 (복사해서) 반환하도록 설계하는 것이 일반적입니다.


  • Prefix ++ operator : reference type 혹은 object type 둘다 반환값으로 가능.
  • Suffix ++ operator : reference type으로 반환값을 줄 수 없음. 오로지 object type으로만 반환값을 줄 수 있음.




상기 [코드 2]에서 Prefix ++(빨간색 부분)의 반환 값을 reference type(VInt&) 가 아닌 object type(VInt)로 수정을 해서(&를 빼고) 다시 테스트를 해 보았습니다.


[코드 4]
VInt operator ++(int) // ... Prefix increment (반환값이 object type임. &을 뺌)

[실행 4]
3


객체의 복사가 이루어 지기 때문에 "2+2"(같은 object를 더하기)가 아닌 "1+2"(서로 다른 object간의 덧셈)가 수행이 되면서 4가 아닌 3이 출력되는 것을 확인할 수 있습니다.




[결론]


  • operator overloading의 반환값을 reference로 하느냐, object(copy)로 하느냐는 클래스 설계자 마음대로임.
  • 코딩을 할 때에는 ambiguity를 줄여 주게끔 하는 것이 상책. ^^




[다운로드]

suffix_increment_test.cpp

VInt all class file