연산자 오버로딩

연산자 오버로딩(operator overloading)은 객체 지향 컴퓨터 프로그래밍에서 다형성의 특정 경우로 다른 연산자들이 함수 인자를 통해서 구현을 할 때를 말한다. 연산자 오버로딩은 일반적으로 언어, 프로그래머, 또는 두 가지 모두에 의해 정의된다.

연산자 오버로딩은 프로그램 개발자가 "가까운 목표 범위(closer to the target domain)" 표기법을 사용할 수 있고 사용자 정의 타입과 비슷한 수준을 허락하기 때문에 언어에 내장된 형식으로 구문을 지원한다. 그것은 쉽게 함수 호출을 사용하여 모방할 수 있다; 예를 들어, 정수 a, b, c를 생각하면:

 a + b * c

연산자 오버로딩을 지원하는 언어에서, '*' 연산자는 '+' 우선 순위보다 높고, 이것은 효과적으로 좀 더 간결한 작성 방법일 것이다:

 add (a, multiply (b,c))

예시 
사용자 정의 유형의 "Time"에 추가 허용하는 연산자 오버로딩의 예시 (C++에서):

 Time operator+(const Time& lhs, const Time& rhs) {
     Time temp = lhs;
     temp.seconds += rhs.seconds;
     if (temp.seconds >= 60) {
         temp.seconds -= 60;
         temp.minutes++;
     }
     temp.minutes += rhs.minutes;
     if (temp.minutes >= 60) {
         temp.minutes -= 60;
         temp.hours++;
     }
     temp.hours += rhs.hours;
     return temp;
 }

덧셈은 왼쪽과 오른쪽 피연산자를 의미하는 이항 연산이다. C++에서, 전달되는 인자는 피연산자이며, 임시 개체가 반환 값이다.

연산자는 또한 클래스 메서드를 정의할 수 있으며, 숨겨진 this 인수로 lhs를 대체한다. 그러나 이것은 왼쪽 피연산자 타입 Time의 효과와 this는 수정 가능하게 될 수 있는 lvalue(왼쪽 값)을 추정한다.

 Time Time::operator+(const Time& rhs) const {
     Time temp = *this;  /* 'this' 값 복사, 이것은 수정되지 않는다. */
     temp.seconds += rhs.seconds;
     if (temp.seconds >= 60) {
         temp.seconds -= 60;
         temp.minutes++;
     }
     temp.minutes += rhs.minutes;
     if (temp.minutes >= 60) {
         temp.minutes -= 60;
         temp.hours++;
     }
     temp.hours += rhs.hours;
     return temp;
 }

this에서 작동되는 클래스 메서드로 정의된 단항 연산자는 명백한 인수를 받을 일은 없을 거라고 한다:

 bool Time::operator!() const {
     return ((hours == 0) && (minutes == 0) && (seconds == 0));
 }

비평 
연산자 오버로딩은 프로그래머가 연산자에 완전히 다른 의미를 줄 수 있기 때문에 비판을 받아왔다. 예를 들어, C++에서 연산자 << 사용시 :
a << 1
a는 정수 형식의 경우 1 비트로 남아있는 변수 a의 비트를 쉬프트한다, 하지만 만약 a가 출력 스트림일 경우 그러면 위의 코드는 출력 스트림에 "1" 을 출력한다.

이 비판에 대한 일반적인 답변은 동일한 인자뿐 아니라 오버로딩을 함수에 적용되는 것이다. 또한 심지어는 오버로딩이 없는 상태에서 프로그래머는 이름에서 예상되는 것과 완전히 다른 일을 하는 함수를 정의할 수 있다. 남아있는 문제는 그 언어와 같은 C++ 연산자 기호의 제한된 집합을 제공하고 따라서 프로그래머의 새로운 작업에 대한 보다 적절한 연산자 기호를 선택 옵션에서 제거한다.

또, 연산자와 함께 더 많은 미묘한 문제는 수학에서 특정 규칙이 잘못 예상 또는 실수로 간주 될 수 있다는 것이다. 예를 들면 +의 교환 법칙 (예:  a + b == b + a ) 이 항상 적용되지 않는다; 피연산자가 문자열일 때 이 예제가 발생한다, +는 일반적으로 오버로딩이 있기 때문에 문자열 연결을 수행한다. (예: "school" + "bag"은 "schoolbag"을 산출, 이것은 "bag" + "school"은 "bagschool"을 산출하는 것과 다르다). 일반 계산 인수로 수학에서 직접 제공한다: + 는 정수에서 교환법칙이 성립 (그리고 일반적으로 어떠한 실제 숫자) 하는 동안, 그것은 변수의 다른 "종류"에 대한 교환법칙이 성립하지 않는다. 반올림 오류로 인해 실제 부동소수점 값에서 그것은 그 + 도 연관되지 않다고 더 지적할 수 있다. 또 다른 예를 들어: 이항연산 * (곱셈) 은 정수에 대한 교환법칙이 성립하지만, 행렬 곱셈의 경우 교환법칙이 성립하지 않는다.

목록 
몇 가지 일반적인 프로그래밍 언어의 분류는 프로그래머와 연산자가 미리 정의된 집합으로 오버로드 가능 여부를 나타낸 것이다.

연산자 오버로딩의 연대순

1960년대 
ALGOL 68 기능은 연산자 오버로딩을 허용한다.

연산자 오버로딩 ¬, =, ≠ 그리고 abs가 정의된 ALGOL 68 언어 기능 (페이지 177)에서 추출:
 10.2.2. 부울 피연산자에 대한 연산
 a) op ∨ = (bool a, b) bool:( a | true | b );
 b) op ∧ = (bool a, b) bool: ( a | b | false );
 c) op ¬ = (bool a) bool: ( a | false | true );
 d) op = = (bool a, b) bool:( a∧b ) ∨ ( ¬b∧¬a );
 e) op ≠ = (bool a, b) bool: ¬(a=b);
 f) op abs = (bool a)int: ( a | 1 | 0 );
특별한 선언이 연산자를 오버로드하기 위해 필요하지 않는다는 점을 참고하고, 프로그래머는 새로운 연산자를 자유롭게 만들 수 있다.

1980년대 
에이다는 에이다 83 언어 표준의 출판과 함께 처음 소개됨에서 연산자 오버로딩을 지원한다. 그러나, 언어의 설계자는 새로운 연산자의 정의를 허용하지 않도록 선택한다: 단지 언어의 기존 연산자 (예 : "+", "*", "and" 등 식별자 새로운 기능을 정의하여)를 오버로딩할 수 있다. 언어의 후속 개정 (1995년과 2005년)은 기존 연산자의 오버로딩에 대한 제한을 유지한다.

C++의 연산자 오버로딩은 ALGOL 68에서 더 수정되었다.

1990년대 
Sun은 자바 언어로 오버로딩 연산자를 포함하지 않기로 선택한다.

2001년 
마이크로소프트는 C#에서 연산자의 오버로딩을 포함했다.

같이 보기 
 함수 오버로드
 다형성
 함수 (프로그래밍)
 연산자 (프로그래밍)
 C와 C++에서의 연산자

참조 

ALGOL 68 코드 예시에 관한 문서
연산자 (프로그래밍)
프로그래밍 구성체