매개변수의 데이터형이 서로 다르더라도, 그 파라미터로 선언된 데이터형의 값에 따라서 동일한 함수 이름으로 동일한 연산을 수행하도록 하는 것
이러한 오버로딩의 개념을 연산자까지 확장하여서 C++에서 연산자들에게 다중적인 의미를 부여하는 것
ex. *는 주소에 적용되면 그 주소에 저장되어 있는 값을 산출하고, (*data)
두 값 사이에 적용되면 그 두 값의 곱을 산출한다 (2 * 4)
C++는 이미 피연산자의 개수/데이터형을 판단하여 어떤 연산을 수행할지 이미 결정하고 있다
sum이라는 함수를 오버로딩 된 덧셈 연산자를 사용하는 버전으로 변환하는 것은 어렵지 않다
sum이라는 함수의 이름만 바꿔주면 된다
Time sum(Time&);
Time operaror(Time&);
이렇게 함수의 이름을 operator로 바꾸고, 어떠한 산술 연산자를 오버로딩할 것인지 정의해 주면 된다
Time operator+(Time&);
이렇게 덧셈을 오버로딩할 것이기 때문에 operator 뒤에 +을 붙이면 된다
이렇게 operator+로 정의하였기 때문에,
Time 객체 내에서는 원래의 +가 가지는 산술 연산이 아니라 여기서 정의한 operator+ 함수에 맞게 변형되어서 작동하게 된다
day1.operator+(day2);
이렇게 함수를 호출하듯이 사용하여도 되고,
day1 + day2
이렇게 사용하여도 된다
두번째 경우, 함수의 이름을 operator+로 정의하였기 때문에 그냥 덧셈처럼 사용하더라도 Time 객체 내에서는 원래 덧셈 산술 연산이 아니라 operator+ 함수에 맞게 변형되어서 작동된다
지금까지는 클래스의 private 부분에 접근할 수 있는 유일한 통로가 바로 public 클래스에 정의되어 있는 메소드였다
C++이 가진 또다른 통로가 바로 프렌드이다
함수를 어떤 클래스에 대해 friend로 만들게 된다면 그 friend 함수는 클래스의 멤버 함수들이 가지는 것과 동등한 접근 권한을 갖는다
즉, public 영역에 정의되어 있는 멤버 함수들처럼 friend 함수가 private 변수에 접근할 수 있게 된다
이항 연산자를 오버로딩하면 프렌드를 만들 필요성이 생긴다
(이항 연산자: 두 개의 피연산자를 요구하는 연산자)
Time a, b;
a = b * 3;
만약 위와 같이 operator*를 만들었다면,
Time 클래스 객체(b)와 int형 변수의 연산을 통해서 Time 클래스 객체(a)의 값을 저장하게 된다
함수의 매개변수로 취하는 것이 int형 변수이기 때문에 연산자를 오버로딩하는 방법으로는 해결할 수 없는 문제가 생긴다
=> 이를 프렌드로 해결!
friend Time operator*(int, Time);
이는 멤버 함수가 아니므로 멤버 연산자 점(.)이나 화살표(->)를 이용할 수 없다
멤버 함수는 아니지만 멤버 함수와 동등한 접근 권한을 가진다
= 멤버 함수는 아니지만 private 영역에 정의되어 있는 멤버 변수에 접근할 수 있다
Time operator*(int n, Time& t) {
Time result;
long resultWin = t.hours * n * 60 + t.mins * n;
result.hours = resultWin / 60;
result.mins = resultWin % 60;
return result;
}
멤버 함수가 아니기 때문에 사용 범위 결정 연산자(className::)를 사용하지 않고, friend 키워드도 사용하지 않는다
이렇게 정의하고 나서 main에서 t2 = 3 * t1 을 수행하게 된다면
t2 = operator*(3, t1);으로 해석되어 연산을 수행하게 된다
그러나 t1과 3의 순서를 바꾸게 되면 operator*와 순서가 다르므로 작동하지 않는다
Time operator*(int); // Time 객체가 함수를 호출할 것이기 때문에 매개변수 int 하나이렇게 되면 int, 클래스 객체의 순서가 바뀌어도 함수가 잘 작동하게 된다
꺽쇠 연산자. 스트림 추출 연산자라고 하기도 한다
프렌드를 통해 오버로딩할 수 있다
cout과 출력될 객체 하나, 총 두 개의 피연산자가 필요
cout << x << y;는 앞에서부터 진행되므로, (cout << x) << y;와 같이 괄호로 묶어도 상관이 없다
<< 연산자는 iostream에 정의되어 있는 객체를 좌항에 대해 피연산자로 요구하고 있고, 그것에 대한 결과값 역시 좌항에 위치할 수 있다
friend std::ostream& operator<<(std::ostream&, Time&);
std::ostream& operator<<(std::ostream& os, Time& t) {
os << t.hours << "시간" << t.mins << "분";
return os;
}
여기서 << 연산자는 좌항의 값으로 ostream의 객체를 요구하고 있기 때문에 리턴형이 os의 참조라는 것을 주목할 필요가 있다
즉, 이 함수가 ostream의 객체에 대한 참조를 리턴한다는 것을 의미한다
기본적으로 클래스는 상속을 전제하에 설계되어 있기 때문에 iostream, ostream에 대한 참조가 모두 허용된다