연산자 오버로딩

'''연산자 오버로딩'''(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 
a는 정수 형식의 경우 1 비트로 남아있는 변수 a의 비트를 쉬프트한다, 하지만 만약 a가 출력 스트림일 경우 그러면 위의 코드는 출력 스트림에 "1" 을 출력한다.
이 비판에 대한 일반적인 답변은 동일한 인자뿐 아니라 오버로딩을 함수에 적용되는 것이다. 또한 심지어는 오버로딩이 없는 상태에서 프로그래머는 이름에서 예상되는 것과 완전히 다른 일을 하는 함수를 정의할 수 있다. 남아있는 문제는 그 언어와 같은 C++ 연산자 기호의 제한된 집합을 제공하고 따라서 프로그래머의 새로운 작업에 대한 보다 적절한 연산자 기호를 선택 옵션에서 제거한다.
또, 연산자와 함께 더 많은 미묘한 문제는 수학에서 특정 규칙이 잘못 예상 또는 실수로 간주 될 수 있다는 것이다. 예를 들면 +의 교환 법칙 (예:  a + b == b + a ) 이 항상 적용되지 않는다; 피연산자가 문자열일 때 이 예제가 발생한다, +는 일반적으로 오버로딩이 있기 때문에 문자열 연결을 수행한다. (예: "school" + "bag"은 "schoolbag"을 산출, 이것은 "bag" + "school"은 "bagschool"을 산출하는 것과 다르다). 일반 계산 인수로 수학에서 직접 제공한다: + 는 정수에서 교환법칙이 성립 (그리고 일반적으로 어떠한 실제 숫자) 하는 동안, 그것은 변수의 다른 "종류"에 대한 교환법칙이 성립하지 않는다. 반올림 오류로 인해 실제 부동소수점 값에서 그것은 그 + 도 연관되지 않다고 더 지적할 수 있다. 또 다른 예를 들어: 이항연산 * (곱셈) 은 정수에 대한 교환법칙이 성립하지만, 행렬 곱셈의 경우 교환법칙이 성립하지 않는다.
몇 가지 일반적인 프로그래밍 언어의 분류는 프로그래머와 연산자가 미리 정의된 집합으로 오버로드 가능 여부를 나타낸 것이다.
 연산자
 오버로딩 불가능
 오버로딩 가능
 신규 정의
 
* ML
* Pico
* 프롤로그
 
* ALGOL 68
* Eiffel
* 포트란
* F#
* 하스켈
* 아이오
* 펄 6
* R
* 스칼라
* 스몰토크
 제한된 집합
 
* C
* 자바
* 자바스크립트
* 모듈라-2
* 오브젝티브-C
* 파스칼
* 베이직
* 에이다
* C++
* C#
* D
* 프리베이직
* 그루비
* 루아
* 델파이 (2005년)
* 오브젝트 파스칼 (프리 파스칼)
* PHP (magic 메서드이나 ArrayAccess 인터페이스나 운영자 확장을 사용)
* 펄
* 파이썬
* 루비
* 비주얼 베이직 2005
* 코틀린
=== 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 코드 예시에 관한 문서
분류:연산자 (프로그래밍)
분류:프로그래밍 구성체