[C++] 연산자 다중 정의

강민석·2022년 10월 18일
0

이것이 C++이다

목록 보기
4/8
post-thumbnail

5.1 연산자 함수란?

  • '연산자 함수': 연산자를 이용하듯 호출할 수 있는 메서드
  • 연산자 함수는 절대 오류가 발생해서는 안된다.
  • 절대로 논리 연산자들을 다중 정의해서는 안된다.

5.2 산술 연산자

  • 숫자가 아닌 것도 경우에 따라 사칙연산이 가능할 수 있다!
#include <iostream>
using namespace std;

class CMyInteger {
public:
    // 변환 생성자
    CMyInteger(int param): data(param) {
        cout << "CMyInteger(int)" << endl;
    }

    // 복사 생성자
    CMyInteger(const CMyInteger &rhs): data(rhs.data) {
        cout << "CMyInteger(const CMyInteger &)" << endl;
    }

    // 이동 생성자
    CMyInteger(const CMyInteger &&rhs): data(rhs.data) {
        cout << "CMyInteger(const CMyInteger &&)" << endl;
    }

    // 형변환
    operator int() { return data; }

    // + 연산자
    CMyInteger operator+(const CMyInteger &rhs) {
        cout << "operator+" << endl;
        int temp = this->data + rhs.data;
        CMyInteger result(temp);
        return result;
    }

    // = 연산자(대입 연산자)
    CMyInteger operator=(const CMyInteger &rhs) {
        cout << "operator=" << endl;
        data = rhs.data;
        return *this;
    }

private:
    int data;
};

int main(int argc, char* argv[]) {
    cout << "***Begin***" << endl;
    CMyInteger a(0), b(1), c(2);
    a = b + c;
    // b+c 연산 수행
    // -> 임시 객체를 생성하기 위해 이동 생성자가 호출된다.
    // -> 생성된 임시 객체를 대입 연산자를 통해  a에 대입한다.
    cout << "****End****" << endl;
}

/*
출력:
    ***Begin***
    CMyInteger(int)
    CMyInteger(int)
    CMyInteger(int)
    operator+ -> + 연산자 호출
    CMyInteger(int) -> + 연산자 함수 내부의 result 객체 생성
    CMyInteger(const CMyInteger &&) -> 임시 객체를 생성하기 위해 이동 생성자가 호출된다.
    operator= -> 대입 연산자가 호출되어 임시 객체의 값을 대입한다.
    ****End****
*/
  • 연산자 함수는 다중 정의가 가능하다.

  • CMyInteger타입과 int 타입의 사칙연산을 지원하고 싶다면 다음과 같이 정의하면 된다.
    CMyInteger operator+(int param)

  • 사실 cout 객체는 전역 변수로 존재하는 ostream 클래스의 인스턴스고, <<,>> 등의 연산자를 제공한다.

5.3 대입 연산자

  • 대입 연산자의 다중 정의
  • 다음과 같은 코드는 문법상의 오류는 없으나, 실행 시 심각한 오류가 발생할 수 있다.
int main(int argc, char* argv[]) {
    CMyData a(0), b(5);

    a = a;
    cout << a << endl;
    return 0;
}
  • 자기 자신에게 단순 대입 연산을 실행하는 것이 적절하지는 않으나, 문법적으로 오류가 있는 것도 아니다.
  • 따라서 해당 케이스에 대해 정상적으로 작동할 수 있도록 다음과 같이 처리를 해주어야 한다.
void operator=(const CMyData &rhs) {
    // r-value가 자기 자신이면 대입을 수행하지 않는다.
    if(this == &rhs) {
        return;
    }

    delete p_pnData;
    m_pnData = new int(*rhs.m_pnData);
}
  • 다음의 경우에도 오류가 발생한다.
int main(int argc, char* argv[]) {
    CMyData a(0), b(5), c(10);

    a = b = c;
    cout << a << endl;
    return 0;
}
  • b = c라는 연산의 반환값이 void이므로, a에는 어떠한 값도 대입되지 않는다.
    • voidl-value의 형식으로 취할 수 없다.
  • 다음과 같이 대입 연산자 함수의 반환 형식을 참조자로 설정하여 문제를 해결할 수 있다.
CMyData& operator=(const CMyData &rhs) {
    if(this == &rhs) {
        return *this;
    }

    delete p_pnData;
    m_pnData = new int(*rhs.m_pnData);

    return *this;
}

5.3.1 복합 대입 연산자

5.3.2 이동 대입 연산자

5.4 배열 연산자

  • 배열 연산자의 두 가지 형태
// l-value로 사용되는 경우를 고려해야 한다.
// 일반적인 경우에는 첫 번째 선언이 사용된다.
int& operator[](int index);

// 두 번째 선언은 상수형 참조를 통해서만 호출할 수 있다.
// 오직 r-value로만 사용된다.
int operator[](int index) const;

5.5 관계 연산자

  • 상등 및 부등 연산자와 비교 연산자를 합쳐, 관계 연산자라 한다.
  • 관계 연산자의 반환값의 종류는 int이다.(참이면 1, 거짓이면 0)
int 클래스이름::operator==(const 클래스이름 &);
int 클래스이름::operator!=(const 클래스이름 &);

5.6 단항 증감 연산자

  • 단항 증가 연산자: ++
  • 단항 감소 연산자: --
  • 피연산자의 어느쪽에 붙는지에 따라 '전위식'과 '후위식'으로 나뉜다.
int operator++(); // 전위식
int operator++(int); // 후위식

0개의 댓글