Language/C++

[C++] OOP(객체지향)의 특성 - 연산자 오버로딩

Return 2022. 6. 6. 17:07

Introduce 

임의의 클래스끼리 연산을 할 수 있을까요?  평소 하는대로 class끼리 덧셈을 한 결과입니다. 

#include <iostream>
using namespace std;

class Position{
    public:
    int _x;
    int _y;
};

int main(){
    Position pos1;
    pos1._x = 0;
    pos1._y = 0;
    
    Position pos2;
    pos2._x = 1;
    pos2._y = 1;

    Position pos3;
    pos3 = pos1 + pos2;	// 컴파일 에러

    return 0;
}

위에서 처럼 피연산자의 형식(type)이 Position이고 이와 일치하는 +연산자가 없다는 에러를 보이고 있습니다. 이번 시간의 목표는 새로운 연산자 type끼리 작용을 할 수있게 만들어주는 것입니다. 

연산자 오버로딩 vs 함수 오버로딩 

연산자는 함수와 다르게 피연산자의 개수/타입이 정해져 있습니다. 연산자 오버로딩을 하기 위해서는 [연산자 함수]를 정의해야되며, 함수도 멤버함수, 전역함수가 존재하는 것처럼, 연산자 함수도 두가지 방식으로 만들 수 있습니다. 

멤버 연산자 함수 

  • a op b 형태에서 왼쪽을 기준으로 실행된다.(a가 클래스여야 가능. a를 기준 피연산자라 한다.)
  • 한계 : a가 클래스가 아니면 못한다. 
#include <iostream>
using namespace std;

class Position
{
public:
    Position operator+(Position arg)
    {
        Position pos;
        pos._x = _x + arg._x;
        pos._y = _y + arg._y;

        return pos;
    }
    Position operator+(int arg)
    {
        Position pos;
        pos._x = _x + arg;
        pos._y = _y + arg;

        return pos;
    }

public:
    int _x;
    int _y;
};

int main()
{
    Position pos1;
    pos1._x = 0;
    pos1._y = 0;

    Position pos2;
    pos2._x = 1;
    pos2._y = 1;

    Position pos3;
    pos3 = pos1 + pos2;
    pos3 = pos1.operator+(pos1); // 동일 표현
    cout << pos3._x << pos3._y << endl;

    Position pos4 = pos3 + 1;
    pos4 = pos3.operator+(1); // 동일 표현
    cout << pos4._x << pos4._y << endl;
    return 0;
}

전역 연산자 함수

a op b 형태라면 a,b모두 연산자 함수의 피연산자로 만들어 줍니다. class 밖에 전역함수로 만들어줍니다. 

Position operator+(int a, Position b)
{
    Position ret;
    ret._x = b._x + a;
    ret._y = b._y + a;
    return ret;
}

유의사항 

멤버연산자함수와 전역연산자함수를 알아봤습니다. 멤버연산자에서 안되던 기능을 전역 연산자함수를 통해 해결하였지만, 마찬가지로 전역 연산자함수에서 안되지만 멤버연산자에서는 되는 몇가지 경우가 있습니다. 

1. 대입 연산자 [=]

대입연산은 return값으로 자기 자신의 참조값으로 해주는 경우가 많습니다. 

// only 멤버함수연산자만 가능
Position &operator=(int arg) // 리턴값을 자기자신의 참조값으로 해주는 경우가 많다.
{
    _x = arg;
    _y = arg;

    return *this; // this가 내 주소를 가리키고 있으니깐 그 주소의 참조값 반환
}

2. 복사 생성자 

복사 대입 생성자가 특별대우를 받는 이유는 말 그대로 객체가 복사되길 원하는 특징 때문입니다. 추후 동작할당 시간에 더 자세히 알아보겠습니다. 

Position &operator=(const Position &arg) // 복사대입연산자
{
    _x = arg._x;
    _y = arg._y;

    return *this; 
}

단항 연산자 오버로딩

Position &operator++()		// 전위형 ++a
{
    _x++;
    _y++;
    return *this;
}

Position operator++(int)	// 후위형 a++
{
    Position ret = *this;
    _x++;
    _y++;
    return ret;
}