C++ Chapter 9.6 : 증감 연산자 오버로딩

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


chapter 9. 연산자 오버로딩 : 증감 연산자 오버로딩

증감 연산자 : ++, --

추가적인 설명은 이전 포스트인 9.1 연산자 오버로딩 시작하기 참고하기

증감 연산자는 전위, 후위를 구분해야 한다.


🔔 ‘전위’ 증감 연산자 오버로딩

int a = 2;

cout << ++a << endl;  // 3 출력
  • 이처럼 전위 증감 연산자는 값이 1만큼 증감하는게 바로 반영이 되야한다.

따라서 전위 증감연산자는 자기 자신을 참조로 리턴 해야한다.


전역 함수로 구현하기

#include <iostream>

using namespace std;

class Digit
{
private:
	int m_digit;
public:
	Digit(int digit = 0) : m_digit(digit) {}

	friend ostream & operator << (ostream &out, const Digit &d)  // 전역 함수
	{
		out << d.m_digit;
		return out;
	}

	friend Digit & operator ++ (Digit & digit) // ⭐전역 함수
	{
		++digit.m_digit;
		return digit;
	}
};


int main()
{
	Digit d(5);

	cout << ++d << endl;  // 6 출력
	cout << d << endl;  // 6 출력

	return 0;
}
  • 증감 연산자는 피연산자를 1개 필요로 한다.
    • 전역 함수로 구현하니 인수 1개를 받아야 한다.
  • 인수 👉 Digit 타입의 객체의 참조를 받는다
    • 증가 시켜주어야 하니 const는 붙이지 않아야 한다.
    • 인수로 넘겨 준 그 해당 객체의 멤버 값을 변경시킬거라 참조로 받아야 한다.
  • 리턴 타입 👉 Digit 타입의 객체의 참조를 리턴한다.
    • 인수로 받은 Digit 그 객체 그대로를 다시 내보낸다.


멤버 함수로 구현하기

#include <iostream>

using namespace std;

class Digit
{
private:
	int m_digit;
public:
	Digit(int digit = 0) : m_digit(digit) {}

	friend ostream & operator << (ostream &out, const Digit &d) // 전역 함수
	{
		out << d.m_digit;
		return out;
	}

	Digit & operator ++ ()  // ⭐멤버 함수
	{
		++m_digit;
		return *this; 
	}
};

int main()
{
	Digit d(5);

	cout << ++d << endl;
	cout << d << endl;

	return 0;
}
  • 증감 연산자는 피연산자를 1개 필요로 한다.
    • 멤버 함수로 구현하니 인수는 필요 없다.
  • 자기 자신(Digit타입 객체)이 곧 피연산자다.
  • 리턴 타입 👉 Digit 타입의 객체의 참조를 리턴한다.
    • 자기 자신(Digit타입 객체)을 리턴해야 하니 *this을 리턴해준다.


🔔 ‘후위’ 증감 연산자 오버로딩

int a = 2;

cout << a++ << endl;  // 2 출력
cout << a << endl;  // 3 출력
  • 이처럼 후위 증감 연산자는 값이 1만큼 증감하는게 세미 콜론을 만난 후에 반영된다.

후위 증감연산자의 구현

friend Digit operator ++ (Digit & digit, int) // 전역 함수 구현시
{
    Digit temp(digit.m_digit);
		++digit;
		return temp;
}

Digit operator ++ (int)  // 멤버 함수 구현시
{
	  Digit temp(m_digit); 
	  ++(*this); 
	  return temp; 
}
  1. 전위 증감 연산자와 구분하기 위해 dummy 매개변수인 int를 둔다.
    • 전위 증감 연산자는 리턴 타입이 참조기 때문에 이 점에서 후위 연산자와 구분이 되기는 하지만 함수의 오버로딩에서 리턴 타입은 구분 기준이 되지 않는다. 참고 포스트
    • 따라서 아무 역할도 하지 않는(dummy), 그저 전위 증감 연산자와 구분하는데 도움이 되기 위한 int를 매개변수 자리에 둔다.
  2. 후위 증감 연산자는 연산의 결과가 바로 반영되지 않기 때문에 미리 연산 전의 값을 옮겨놓은 다음에 연산을 한다. 그리고 임시 저장해 둔 연산 전의 값을 리턴해준다.
    • 증가 시킬 때 '전위' 증감 연산자를 필요로 하기 때문에 후위 연산자 오버로딩만 하지 말고 전위 연산자 오버로딩도 같이 해놓자.
  3. 전위 증감 연산자와 다르게 자기 자신을 참조로 리턴 하면 안되고 일반적인 call by value 타입으로 리턴 해야한다.
    • 증가시키기 전의 값을 미리 옮겨 두었던 그 임시 객체를 리턴해야 하기 때문에


전역 함수로 구현하기

#include <iostream>

using namespace std;

class Digit
{
private:
	int m_digit;
public:
	Digit(int digit = 0) : m_digit(digit) {}

	friend ostream & operator << (ostream &out, const Digit &d)  // 전역 함수
	{
		out << d.m_digit;
		return out;
	}

  //prefix
	friend Digit & operator ++ (Digit & digit) // ⭐전역 함수
	{
		++digit.m_digit;
		return digit;
	}

  //postfix
	friend Digit operator ++ (Digit & digit, int) // ⭐전역 함수
	{
		Digit temp(digit.m_digit);
		++digit;
		return temp;
	}
};


int main()
{
	Digit d(5);

	cout << d++ << endl;   // 5 출력
	cout << d << endl;    // 6 출력

	return 0;
}
  • 증감 연산자는 피연산자를 1개 필요로 한다.
    • 전역 함수로 구현하니 인수 1개를 받아야 한다.
    • 사실 전위 증감 연산자와의 구분(오버로딩)을 위하여 dummy변수인 int가 하나 붙어있긴 하지만 인수는 1개만 받는다.
  • 인수 👉 Digit 타입의 객체의 참조를 받는다
    • 증가 시켜주어야 하니 const는 붙이지 않아야 한다.
    • 인수로 넘겨 준 그 해당 객체의 멤버 값을 변경시킬거라 참조로 받아야 한다.
  • 구현
    1. Digit temp(digit.m_digit);
      • 인수로 넘겨받은 digit 객체를 Digit 타입의 임시 객체 temp를 생성하여 이곳에 옮겨 놓는다.
    2. ++digit;
      • 실제로 digit 객체를 증가 연산 시킨다.
      • 이때 오버로딩된 전위 증감 연산자가 호출된다.
    3. return temp
      • 미리 옮겨 놓았었던 증가시키기 전의 digit 객체인 임시 객체 temp를 리턴한다.
  • 리턴 타입 👉 Digit 타입의 객체를 call by value로 리턴한다.
    • 증가시키기 전의 digit 객체의 정보를 복사해 저장해두었던 임시 객체 temp를 리턴한다.
    • Digit& 참조로 리턴하면 안된다
      • 임시 객체를 리턴할텐데 temp임시 객체는 지역변수라 함수가 끝나지면 사라지기 때문이다. 사라진 공간을 참조하게 되는 것이나 마찬가지이다.
      • 그냥 temp임시 객체를 call by value로 리턴하면 임시 공간에 이 temp 객체가 복사되고 그 임시 공간이 R-value로서 리턴되는 식이라 문제가 없다.
      • 참고 포스트


멤버 함수로 구현하기

#include <iostream>

using namespace std;

class Digit
{
private:
	int m_digit;
public:
	Digit(int digit = 0) : m_digit(digit) {}

	friend ostream & operator << (ostream &out, const Digit &d)
	{
		out << d.m_digit;
		return out;
	}

	//prefix
	Digit & operator ++ ()
	{
		++m_digit;
		return *this; 
	}

	//postfix
	Digit operator ++ (int)
	{
		Digit temp(m_digit); 
		++(*this); 
		return temp; 
	}
};

int main()
{
	Digit d(5);

	cout << d++ << endl;   // 5 출력
	cout << d << endl;    // 6 출력

	return 0;
}
  • 증감 연산자는 피연산자를 1개 필요로 한다.
    • 멤버 함수로 구현하니 인수는 필요 없다.
  • 자기 자신(Digit타입 객체)이 곧 피연산자다.
    • 사실 전위 증감 연산자와의 구분(오버로딩)을 위하여 dummy변수인 int가 하나 붙어있긴 하지만 인수는 받지 않는다.
  • 구현
    1. Digit temp(m_digit);
      • 자기 자신의 멤버값과 똑같은 멤버를 가진 Digit 타입의 임시 객체 temp를 생성한다.
      • 증가 전 자신의 정보를 미리 다른 곳에 옮겨 놓은 것이나 마찬가지.
    2. ++(this);*
      • 자기 자신을 증가 연산 시킨다.
      • 이때 오버로딩된 전위 증감 연산자가 호출된다.
    3. return temp
      • 미리 옮겨 놓았었던 증가시키기 전의 자기 자신을 복사해 둔 임시 객체 temp를 리턴한다.
  • 리턴 타입 👉 Digit 타입의 객체를 call by value로 리턴한다.
    • 증가시키기 전의 자기 자신의 정보를 복사해 저장해두었던 임시 객체 temp를 리턴한다.
    • Digit& 참조로 리턴하면 안된다
      • 임시 객체를 리턴할텐데 temp임시 객체는 지역변수라 함수가 끝나지면 사라지기 때문이다. 사라진 공간을 참조하게 되는 것이나 마찬가지이다.
      • 그냥 temp임시 객체를 call by value로 리턴하면 임시 공간에 이 temp 객체가 복사되고 그 임시 공간이 R-value로서 리턴되는 식이라 문제가 없다.
      • 참고 포스트


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Cpp 카테고리 내 다른 글 보러가기

댓글 남기기