C++의 대입 연산은 여러 개가 사슬처럼 엮일 수 있는 재미있는 성질을 갖고 있습니다.
int x, y, z;
x = y = z = 15; // 대입이 사슬처럼 이어집니다.
대입 연산이 가진 또 하나의 재미있는 특성은 바로 우측 연관(right-associative) 연산이라는 점입니다.
즉, 위의 대입 연산 사슬은 다음과 같으 분석됩니다.
x = (y = (z = 15));
위 코드를 풀어 보면, 15가 z에 대입되고, 그 대입 연산의 결과(갱신된 z)가 y에 대입된 후에, y에 대한 대입 연산의 결과(그러니까 갱신된 y)가 x에 대입된다는 것입니다.
이렇게 대입 연산이 사슬처럼 엮이려면 대입 연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것입니다. 이런 구현은 일종의 관례(convention)인데, 여러분이 나름대로 만드는 클래스에 대입 연산자가 혹시 들어간다면 여러분도 이 관례를 지키는 것이 좋습니다.
1 2 3 4 5 6 7 8 9 10 | class Widget { public: ... Widget& operator=(const Widget& rhs) // 반환 타입은 현재의 클래스에 대한 { // 참조자입니다. ... return *this; // 좌변 객체(의 참조자)를 반환합니다. } ... }; | cs |
"좌변 객체의 참조자를 반환하게 만들자"라는 규약은 위에서 보신 단순 대입형 연산자 말고도 모든 형태의 대입 연산자에서 지켜져야 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Widget { public: ... Widget& operator+=(const Widget& rhs) // +=, -=, *= 등에도 동일한 { // 규약이 적용됩니다. ... return *this; } Widget& operator=(int rhs) // 대입 연산자의 매개변수 타입이 { // 일반적이지 않은 경우에도 ... // 동일한 규약을 적용합니다. return *this; } ... }; | cs |
따르지 않고 코드를 작성하더라도 컴파일이 안 된다거나 하는 것은 아닙니다. 하지만 이 관례는 모든 기본제공 타입들이 따르고 있을 뿐만 아니라 표준 라이브러리에 속한 모든 타입(string, vector, complex, tr1::shared_ptr 등)에서도 따르고 있습니다.
대입 연산자는 *this의 참조자를 반환하도록 만드세요.