연산자 중복(오버로딩)의 2가지 구현 방법
- 클래스의 멤버 함수로 구현
- 외부 함수로 구현하고 클래스에 프렌드 함수로 선언
함수 형식
리턴타입 operator 연산자(매개변수)
Point operator+(const Point& op1); // 멤버 함수
Point operator+(const Point& op1, const Point& op2); // 외부 함수
함수 형식을 정하는 기준(멤버함수, 외부함수)
1. 좌측 피연산자가 클래스인 경우 [클래스 객체 + 클래스 객체], [클래스 객체 + 상수], [클래스 객체++]
-> 클래스 내 멤버 함수로 구현이 가능하다.
2. 좌측 피연산자가 상수(int, double 등)인 경우
-> 외부 함수로 구현하고, friend로 묶어줘야 한다.
연산자 중복 함수의 리턴 타입의 3가지 종류
- 임시 객체를 리턴하는 경우
- 참조를 리턴하는 경우
- 기본 데이터 타입(int, bool 등)을 리턴하는 경우
1. 임시 객체를 리턴하는 경우
→ 임시 객체 리턴 연산 연산의 종류: a+b, a++ ..
a + b의 연산의 경우, 코드에서의 쓰임을 생각해보자.
int a, b;
a + b;
a + b는 위 코드처럼 단독으로 쓰일 수 없다. 왜 그럴까?
a + b는 ‘임시 값’이기 때문이다.
int a, b, c;
c = a + b;
cout << a + b << endl;
그렇기에 위와같이 과 같이 ‘임시 값’은 변수에 대입하거나, 매개변수로써 쓰일 때 사용된다.
a++ 연산의 경우
int a = 5;
cout << a++ << endl; // 5
cout << a << endl; // 6
cout « a++ « endl; 문장에서 a++로 리턴 된 값은 5이다.
하지만 a의 실제 값은 6이 되어있다.
그 말은, a++연산의 결과는 a++가 실행되기 이전의 객체(값) 이라는 뜻이다.
위와 같이 연산의 결과가 ‘임시 값’ 역할을 하는 경우, 연산자 함수 내에서 임시 객체를 생성하여 리턴하고
rvalue 적인 성격을 지녔다고 볼 수 있다. (rvalue 에 관한 설명은 아래에 할 예정)
2. 참조를 리턴하는 경우
→ 참조자 리턴 연산의 종류: a += b, ++a ..
두 연산을 풀어서 쓰면 다음과 같다.
a += b ⇒ a = a + b;
++c ⇒ c = c + 1;
a += b 연산은 왼쪽 피연산자(a)의 값 자체가 수정되어야 한다.
++c 연산 또한 피연산자(c)의 값 자체가 수정되어야 한다.
→ 피연산자가 Lvalue적 속성을 지니고 있다.
결론
연산자를 구현할 때 리턴 값을 정하는 것의 기준은,
연산이 rvalue와 lvalue중 어느 성격을 띄는 지 라고 볼 수 있다.
연산의 결과 변수 자체의 값이 변한다 → 참조(lvalue)
연산의 결과값이 임시 값이다 → 일반리턴(rvalue)
L value & R value
오류를 접할 때, 잘 읽어보면 lvalue와 rvalue라는 단어가 종종 보인다.
이들이 뜻과 각각의 차이점을 알아보자.
L value
Lvalue는 단일 표현식 이후에도 없어지지 않고 지속되는 객체이다.
쉽게 Lvalue는 변수, 함수, 클래스 등을 나타내는 식별자를 의미한다.
a = b + c;
라는 문장이 있을 때, a는 lvalue이다.
반면에, b+c는 표현식 이후 사라지는 ‘임시 값’ 이므로 lvalue가 아니다.
R value
int val = 20;
val = 5 + val;
R value는 해당 표현식이 끝나면 더 이상 참조할 수 없는 값을 의미한다.
위 코드에서 val은 Lvalue이다.
두 번째 코드의 val 의 경우 왼쪽의 val은 여전히 Lvalue이지만,
(20 + val)은 그 자체로 ‘임시 값’이 되어 Rvalue가 되는 것이다.
int main()
{
int x = 3;
const int y = x;
int z = x + y;
int* p = &x;
cout << string("one");
++x;
x++;
}
위 코드에서 rvalue와 lvalue를 구분해보자.
3은 x에 대입되고 나서 참조될 수 없으므로 rvalue이다.
마찬가지로 x + y 또한 참조될 수 없으므로 rvalue이다.
흥미로운 점은, ++x 는 lvalue인 반면에 x++는 rvalue이다.
이유는 x++의 결과는 위에서도 다뤘듯이 '임시 값'을 리턴하기 때문이다.
증가 이전의 값을 임시 객체에 저장해놓고, 원본 변수의 값을 증가시키고 나서 임시 객체를 리턴하는 형식이기 때문이다.