연산자 오버로딩 개요

    • , = , * 등의 연산자를 유저 정의 타입( ex class)dp 대해 사용할 수 있도록 하는 기능
      • Player1 + Player2
  • 유저 정의 타입을 기본 타입 ( int, float, etc)과 유사하게 동작하게 할 수 있음

  • 코드를 보다 이해하기 쉽고, 작성하기 쉽게 만듬

    • 항상 좋은 것은 아님. 직관성과 가독성을 높인다고 생각이 들 경우 활용
  • 대입 연산자( = ) 를 제외하면 자동 생성되지 않으며, 사용자가 구현해 주어야 함

  • 연산자 오버로딩 기능자체도 중요하지만 , 지금까지 배운 모든 내용이 종합적으로 적용되므로 이해하지 못한 내용이 없는지 점검 해야함

예시

#include <iostream>

class Player {

};

int main()
{
	int a = 1;
	int b = 2;
	int c = a + b;

	Player p1; //객체 생성
	Player p2;

	Player p3 = p1 + p2;//불가능

}
  • 위에서 Player 객체의 연산은 왜 불가능 한가?
    • 컴파일러가 어떻게 해야 하는지 모르기 때문에 우리가 지정해줘야 한다.

즉, 우리는 연산자 오버로딩을 통하여 위의 같은 상황에서 p3 = p1 + p2가 성립하게 할 것 이다.

예시 2

  • 숫자 하나를 갖는 Number class를 작성하고, class 사이의 사칙 연산 기능이 필요하다고 가정. 만일 (a+b) * ( c / d )를 계산해야 한다면,
  1. (전역) 함수를 사용해 구현

    Number result = multiply(add(a,b) , divide(c,d));
  1. 멤버 함수를 사용해 구현

    Number result = (a.add(b)).multiply(c.divide(d));

기본 규칙

  • 연산의 우선순위를 바꿀 수는 없음 ( * 는 + 보다 먼저 계산)

  • 단항 , 이항 , 삼항 연산의 교체는 불가능

  • 기본 타입( int , float , etc)에 대한 연산자는 오버로딩 불가능

    • 우리가 만든 클래스에 대해서만 적용 가능하다.
  • 새로운 연산자의 정의 불가

  • 연산자는 멤버 함수 또는 전역 함수로 오버로딩 가능!

    • 단 [],(),→, = 등 몇몇 연산자는 멤버 함수로만 오버로딩 가능

멤버 함수 연산자 오버로딩

컴파일러는 연산자를 해석할 때 특정하게 변환해서 해석을 한다. 우리는 이 양식을 연산자를 오버로딩 하면 된다!

  • 이항 연산자의 멤버 함수로의 선언
    • 이항 연산자 : 피 연산자가 2개 존재

    • 선언 형태( 고정된 형태가 아님 )

      Point operator+ ( const Point& rhs) const;
      Point operator- ( const Point& rhs) const;
      bool operator== ( const Point& rhs) const;
      bool operator< ( const Point& rhs) const;

      operator+ , operator- 자체가 함수 명이다.

    • 사용 예시

      Point p1{ 10, 20};
      Point p2{ 30, 40};
      Point p3 = p1 + p2; //p1.operator + (p2) 로 변환 됨
      p3 = p1 - p2; // p1.operator - (p2) 로 변환됨
      
      if(p1 == p2) //p1.operator == (p2)
      		....
      

예시 코드

#include <iostream>

class Point
{
private:
	int xpos;
	int ypos;
public:
	Point(int x = 0, int y = 0)
		:xpos{ x }, ypos{ y } {}

	void ShowPosition() const
	{
		std::cout << "[" << xpos << "," << ypos << "]" << std::endl;
	}

	Point operator+(Point p)
	{
		std::cout << " + operator called " << std::endl;
	}
};

int main()
{
	Point p1{ 2,3 };
	Point p2{ 3,4 };

	Point p3 = p1 + p2;// p1.operator+ (p2)로 변환 됨
}

위의 코드에서 하나 아쉬운 것이 있다. void operator+()함수를 수정해 보자

Point operator+(const Point& p) const
{
		///나중에 구현
}

위와 같이 const 참조자를 사용하는 것이 좋은 이유는 ?

  1. 우리는 단순히 더하는 작업을 하기 때문에 일단 매개변수 p의 값이 바뀌면 안된다
  2. 복사의 비용을 낮추기 위해서 const 참조자 사용

결과

  • operator 가 호출이 된 것을 볼 수 있다.
  • why?
    • 컴파일러가 p1 + p2를 p1.operator+ (p2)로 변환해서 해석하기 때문에

구현

	Point operator+(const Point& p) const
	{
			return Point{ xpos + p.xpos, ypos + p.ypos };
	}

위의 코드에서 main함수에 p3 = p1 + p2가 선언되어 있음을 명심하자. 현재 해당 함수는 p1에서 호출하고 있기 때문에 xpos,ypos는 p1의 변수, 참조자 p는 p2를 나타낸다.

== 연산자 예시

	#include <iostream>

class Point
{
private:
	int xpos;
	int ypos;
public:
	Point(int x = 0, int y = 0)
		:xpos{ x }, ypos{ y } {}

	void ShowPosition() const
	{
		std::cout << "[" << xpos << "," << ypos << "]" << std::endl;
	}

	Point operator+(const Point& p) const //복사의 비용을 낮추기 위해서 const 참조자 사용, p의 값이 바뀌면 안되기 때문에
	{
		return Point{ xpos + p.xpos, ypos + p.ypos };
	}

	bool operator== (const Point& p) const //return type이 bool인 이유?
	{
		if (xpos == p.xpos && ypos == p.ypos)
			return true;
		else
			return false;
	}


};

int main()
{
	Point p1{ 2,3 };
	Point p2{ 3,4 };

	p1 == p2;

	if (p1 == p2) // 컴파일러는 p1.operator == (p2) 로 변환한다.
	{
		std::cout << "Same!" << std::endl;
	}
}
profile
개발로그

0개의 댓글