프로그래밍 언어/열혈 C++

10. 연산자 오버로딩 1

당장하자 2022. 3. 13. 23:59

연산자 오버로딩

  • 함수를 오버로딩 하는 것 처럼 연산자도 오버로딩할 수 있다.
  • 즉 연산자의 기본 기능 이외 다른 기능을 매개변수에 따라 추가할 수 있다.

 

#include <iostream>
using namespace std;

class Point
{
private:
    int xpos, ypos;
public:
    Point(int x=0, int y=0) : xpos(x), ypos(y)
    { }
    void ShowPosition() const
    {
        cout << "xpos: " << xpos << " ypos: " << ypos << endl;
    }
    Point operator+(const Point &pos)
    {
        Point point(xpos+pos.xpos, ypos+pos.ypos);
        return point;
    }
};

int main()
{
	Point pos1(10, 20);
    Point pos2(3, 4);
    Point pos3;
    pos3 = pos1 + pos2;
    pos3.ShowPosition();
}

 

xpos: 13 ypos: 24

Process returned 0 (0x0)   execution time : 0.013 s
Press any key to continue.

 

pos1 + pos2는 pos1.operator+(pos2)로 해석되어서 컴파일된다. 

이는 operator 키워드를 통한 일종의 약속이다.

 

연산자 오버로딩 방법

  1. 멤버함수에 의한 연산자 오버로딩
  2. 전역함수에 의한 연산자 오버로딩

1의 방법은 위에서 보였다시피 pos1의 멤버함수에 operator+(Point pos)를 선언함으로써 가능하다

 

2의 방법은 

#include <iostream>
using namespace std;

class Point
{
private:
    int xpos, ypos;
public:
    Point(int x=0, int y=0) : xpos(x), ypos(y)
    { }
    void ShowPosition() const
    {
        cout << "xpos: " << xpos << " ypos: " << ypos << endl;
    }
    friend Point operator+(const Point &pos1, const Point &pos2);
};

Point operator+(const Point &pos1, const Point &pos2)
{
    Point pos(pos1.xpos+pos2.xpos, pos1.ypos+pos2.ypos);
    return pos;
}

int main()
{
	Point pos1(10, 20);
    Point pos2(3, 4);
    Point pos3;
    pos3 = pos1 + pos2;
    pos3.ShowPosition();
}

friend(함수내에서 클래스의 private 영역에 접근가능) 선언을 통해서 +연산자에 오버로딩이 되어있다.

 

+= 연산자 오버로딩

Point& operator+=(const Point &pos)
{
    xpos = xpos+pos.xpos;
    ypos = ypos+pos.ypos;
    return *this;
}

 

 

연산자 오버로딩 주의사항

1. 본래의 의도를 벗어난 형태의 연산자 오버로딩은 좋지 않다.

pos1 + pos2를 했는데 곱한 결과가 나온다면 당황스러울 것이다.

 

2. 연산자의 우선순위와 결합성은 바뀌지 않는다.

덧셈과 곱셈이 있다면 곱셈 연산이 먼저 시행된다.

 

3. 매개변수의 디폴트 값 설정이 불가능하다.

자료형에 따라 연산자를 오버로딩 한 함수의 호출이 결정되기에 디폴트 값이 정해질 수 없다.

 

4. 연산자의 순수 기능까지 뺏을 수 없다.

int operator+(const int num1, const int num2)등은 정의할 수 없다.

 

단항 연산자의 오버로딩

Point& operator++()
{
    xpos++;
    ypos++;
    return *this;
}
Point operator-()
{
    Point pos(xpos*(-1), ypos*(-1));
    return pos;
}

전위증가와 후위증가

++pos => pos.operator()

pos++ => pos.operator++(int)

여기서 int는 후위연산을 구분하기 위해 붙이는 것이상의 의미는 없다.

const Point operator++(int)
{
    const Point retobj(xpos, ypos);
    xpos += 1;
    ypos += 1;
    return retobj;
}
const Point operator--(Point &ref, int)
{
    const Point retobj(ref);
    ref.xpos-=1;
    ref.ypos-=1;
    return retobj;
}

반환형에 const 선언

=operator++함수의 반환으로 인해서 생성되는 임시객체를 const로 생성하겠다.

=/= retobj가 const로 선언되어서 ( 반환의 과정에서 새로운 객체가 생성되기때문에 영향을 안준다 -복사생성자 )

 

반환형에 const 선언을 하는 이유는 다음을 막기 위해서이다.

(pos++)++;    // 컴파일 에러
(pos--)--;    // 컴파일 에러

 

(Point형 const 임시객체)++;

(Point형 const 임시객체).operator++();

operator++가 const 함수가 아니기때문에 컴파일 에러가 발생한다.

 

이는 다음을 허용하지 않는 C++의 연산특성을 반영한 결과이다.

int main()
{
    int num = 1;
    (num++)++;    // 컴파일 에러
    (num--)--;    // 컴파일 에러
    
    return 0;
}