C++ 연산자 오버로딩의 세 가지 기본 규칙
C++에서 연산자 오버로딩(operator overloading)을 다룰 때 반드시 따라야 할 기본 규칙이 세 가지 있습니다. 물론 모든 규칙에는 예외가 존재하지만, 이 세 가지 원칙을 지키면 훨씬 안전하고 유지보수하기 좋은 코드를 작성할 수 있습니다.
규칙 1: 의미가 명확하지 않다면 오버로딩하지 마세요
연산자의 의미가 명백하고 논란의 여지가 없는 경우가 아니라면 연산자를 오버로딩해서는 안 됩니다. 대신 적절한 이름을 가진 함수를 제공하는 것이 바람직합니다. 사실 연산자 오버로딩의 가장 근본적인 첫 번째 규칙은 다음 한마디로 요약됩니다.
“하지 마라(Don't do it).”
다소 의외로 들릴 수 있지만, 연산자 오버로딩이 적절한 경우는 실제로 몇 되지 않습니다. 그 이유는 해당 연산자가 응용 분야에서 널리 알려져 있고 그 의미에 이견이 없는 경우가 아니라면, 연산자 사용 뒤에 숨은 의미론(semantics)을 이해하기 어렵기 때문입니다.
규칙 2: 연산자의 잘 알려진 의미를 반드시 따르세요
C++는 오버로딩된 연산자의 의미에 어떠한 제약도 두지 않습니다. 컴파일러는 이항 + 연산자가 오른쪽 피연산자에서 왼쪽 피연산자를 빼는 코드조차 아무 문제 없이 컴파일해 줍니다. 하지만 그런 연산자의 사용자는 a + b 표현식이 b에서 a를 뺀다는 것을 결코 예상하지 못할 것입니다. 따라서 연산자를 오버로딩할 때는 반드시 일반적으로 통용되는 의미를 그대로 유지해야 합니다.
규칙 3: 관련된 연산 집합 전체를 함께 제공하세요
연산자들은 서로 관련되어 있으며, 다른 연산들과도 밀접하게 연결되어 있습니다. 하나만 제공하고 나머지를 누락하면 사용자에게 혼란을 주게 됩니다.
- 타입이
a + b를 지원한다면, 사용자는a += b도 호출할 수 있기를 기대합니다. - 전위 증가
++a를 지원한다면, 후위 증가a++도 동작하리라 기대합니다. a < b비교가 가능하다면,a > b역시 확인할 수 있어야 한다고 생각합니다.- 타입을 복사 생성(copy-construct)할 수 있다면, 대입(assignment) 연산도 가능하리라 기대합니다.
정리
대부분의 경우 연산자 오버로딩은 꼭 필요하지 않으며, 연산자의 의미가 명확하게 정의되어 있고 상황에 잘 맞을 때에만 오버로딩하는 것이 바람직합니다. 무분별한 오버로딩은 코드 가독성을 해치고 버그의 원인이 될 수 있으므로, 위의 세 가지 규칙을 항상 염두에 두시기 바랍니다.
이 글은 Stack Overflow의 답변(https://stackoverflow.com/a/4421708/3719089)에서 영감을 받아 작성되었습니다.