[전문가를 위한 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;
    }
    

15.3 비트 연산자와 논리 연산자 오버로딩하기

15.4 스트림 입출력 연산자 오버로딩하기

15.5 인덱스 연산자 오버로딩하기

15.6 함수 호출 연산자 오버로딩하기

15.7 역참조 연산자 오버로딩하기

15.8 변환 연산자 구현하기

15.9 메모리 할당과 해제 연산자 오버로딩하기