[전문가를 위한 C++] 15장. C++ 연산자 오버로딩하기
Chapter 15. C++ 연산자 오버로딩
15.1 연산자 오버로딩 개요
- 연산자 오버로딩 선택
- 연산자를 오버로딩하는 함수나 메서드를 작성할 때 몇 가지 결정할 사항이 있다.
- 메서드와 전역함수
- 인수 타입에 대한 결정사항
- 리턴 타입에 대한 결정사항
- 동작에 대한 결정사항
- 오버로딩 하면 안 되는 연산자
- 주소 연산자 &
-
이항 부울 연산자 &&, - 콤마 연산자(순차 연산자)
- 우측값 레퍼런스
-
일반 대입 연산자의 프로토타입은 다음과 같다.
T& operator=(const T&);
-
이동 대입 연산자의 프로토타입은 다음과 같다. 이 연산자는 인수를 변경하므로 const인수를 전달할 수 없다.
T& operator=(T&&);
-
대부분의 연산자는 기존 좌측값 레퍼런스를 사용하는 버전과 우측값 레퍼런스를 사용하는 버전이 함께 있어도 상관 없다. 어느 버전이 적합한 지는 클래스마다 다르다.
-
표준 라이브러리에서 사용하는 std::string 클래스는 operator+를 다음과 같이 우측값 레퍼런스로 구현했다.
string operator+(string&& lhs, string&& rhs);
- 이 연산자는 두 인수가 우측값 레퍼런스로 전달됐기 때문에 둘 중 하나에 대한 메모리를 재사용할 수 있다.
- 인수가 우측값 레퍼런스라는 말은 연산이 끝나면 삭제되는 임시 객체라는 뜻이다.
-
이렇게 구현된 operator+는 두 인수의 크기와 용량에 따라 다음 두 가지 동작 중 하나를 수행한다.
return std::move(lhs.append(rhs)); or return std::move(rhs.insert(0, lhs));
-
실제로 std::string에서 제공하는 operator+의 오버로딩 버전들을 보면 좌측값 레퍼런스와 우측값 레퍼런스를 다양하게 조합하고 있다. 인수로 string을 두 개 받는 operator+연산자는 다음과 같다.
string operator+(const string& lhs, const string& rhs); string operator+(string&& lhs, const string& rhs); string operator+(const string& rhs, string&& lhs); string operator+(string&& lhs, string&& rhs);
-
-
15.2 산술 연산자 오버로딩하기
-
단항 뺄셈과 단항 덧셈 연산자 오버로딩하기
SpreadSheetCell SpreadSheetCell::operator-() const { return SpreadSheetCell(-getValue()); }
- operator-는 피연산자를 변경하지 않기 때문에 음수를 갖도록 SpreadSheetCell 객체를 새로 만들어 리턴해야 한다. 다시 말해, 레퍼런스로 리턴할 수 없다.
-
이렇게 오버로딩한 연산자의 사용법은 다음과 같다.
SpreadSheetCell c1(4); SpreadSheetCell c3 = -c1;
- 증가와 감소 연산자 오버로딩하기
- operator++나 operator–의 선행 연산 버전은 인수를 받지 않고, 후행 연산 버전은 int타입의 인수를 하나만 받는다.
-
SpreadSheetCell의 operator++와 operator–를 오버로딩한 예는 다음과 같다.
SpreadSheetCell& operator++(); // 선행 증가 SpreadSheetCell operator++(int); // 후행 증가 SpreadSheetCell& operator--(); // 선행 감소 SpreadSheetCell operator--(int); // 후행 감소
- 선행 연산 버전의 리턴값은 피연산자의 최종 결과와 같다. 따라서 선행 증가 및 감소 연산의 호출 대상 객체는 레퍼런스로 리턴된다.
- 하지만 후행 증가 및 감소 연산의 리턴값은 피연산자의 최종 상태와 다르기 때문에 레퍼런스로 리턴할 수 없다.
-
operator++ 구현 예시
SpreadSheetCell& SpreadSheetCell::operator++() { set(getValue + 1); return *this; }