연산자 오버로딩
연산자 오버로딩(operator overloading)은 객체 지향 컴퓨터 프로그래밍에서 다형성의 특정 경우로 다른 연산자들이 함수 인자를 통해서 구현을 할 때를 말한다. 연산자 오버로딩은 일반적으로 언어, 프로그래머, 또는 두 가지 모두에 의해 정의된다.
연산자 오버로딩은 프로그램 개발자가 "가까운 목표 범위(closer to the target domain)" 표기법을 사용할 수 있고[1] 사용자 정의 타입과 비슷한 수준을 허락하기 때문에 언어에 내장된 형식으로 구문을 지원한다. 그것은 쉽게 함수 호출을 사용하여 모방할 수 있다; 예를 들어, 정수 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 기능은 연산자 오버로딩을 허용한다.[6]
연산자 오버로딩 ¬, =, ≠ 그리고 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에서 더 수정되었다.[7]
1990년대
[편집]Sun은 자바 언어로 오버로딩 연산자를 포함하지 않기로 선택한다.[8][9]
2001년
[편집]마이크로소프트는 C#에서 연산자의 오버로딩을 포함했다.
같이 보기
[편집]각주
[편집]- ↑ “C++ FAQ Lite: What are the benefits of operator overloading?”. 2010년 6월. 2011년 8월 14일에 원본 문서에서 보존된 문서. August 2010에 확인함.
- ↑ 상징적인 이름으로 바이너리 기능 삽입을 호출할 수 있다
- ↑ 포트란 90에서 소개
- ↑ 오버로딩의 유형 클래스를 대신함
- ↑ “Operator Overloading, Free Pascal Manual”. 2011년 6월 23일에 원본 문서에서 보존된 문서. June 2011에 확인함.
- ↑ A. van Wijngaarden, B.J. Mailloux, J.E.L. Peck and C.H.A. Koster; 외. (1968년 8월). “알고리즘 언어 ALGOL 68에 대한 보고서, Section 10.2.2.” (PDF). 2012년 7월 17일에 원본 문서 (PDF)에서 보존된 문서. April 2007에 확인함.
- ↑ Bjarne Stroustrup. “C++의 역사: 1979−1991 - 페이지 12” (PDF). April 2007에 확인함.
- ↑ [1]
- ↑ [2]