[C++] Chapter 10 - 연산자 오버로딩 1

Lee Jeong Min·2021년 1월 12일
0

Cpp

목록 보기
10/16
post-thumbnail

10-1 연산자 오버로딩의 이해와 유형

operator+라는 이름의 함수

함수가 오버로딩이 되어 다양한 기능을 제공하는 것처럼 연산자 또한 오버로딩이 가능하다.
FirstOperationOverloading.cpp

#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 << ", " << ypos << ']' << endl;
	}
	Point operator+(const Point& ref)
	{
		Point pos(xpos + ref.xpos, ypos + ref.ypos);
		return pos;
	}
};

int main(void)
{
	Point pos1(3, 4);
	Point pos2(10, 20);
	Point pos3 = pos1.operator+(pos2); // Point pos3 = pos1+pos2;

	pos1.ShowPosition();
	pos2.ShowPosition();
	pos3.ShowPosition();
	return 0;
}

위의 main함수 내에서 pos3을 pos1.operator+(pos2)라고 정의하였지만 pos1+pos2로 대입을 하여도 컴파일이 가능함. 즉 '+' 자체가 .operator+로 해석이되어 컴파일러가 처리해준다는 것을 알 수 있음.

연산자를 오버로딩 하는 방법 두 가지

  • 멤버함수에 의한 연산자 오버로딩

  • 전역함수에 의한 연산자 오버로딩

    	pos1.operator+(pos2); // 멤버함수 오버로딩
    
    	operator_(pos1, pos2); // 전역함수 오버로딩

두 가지 동시에 오버로딩이 된 경우 멤버함수 먼저 우선시되어 호출

전역함수 기반 오버로딩 예시
GFunctionOverloading

#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 << ", " << 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(void)
{
	Point pos1(3, 4);
	Point pos2(10, 20);
	Point pos3 = pos1 + pos2;

	pos1.ShowPosition();
	pos2.ShowPosition();
	pos3.ShowPosition();
	return 0;
}

위 예제의 friend선언을 보고 operator+ 함수가 Point 클래스의 private 영역에 접근이 가능함 뿐만이 아니라 이 클래스가 +연산에 대해서 연산자 오버로딩이 되어 있음을 확인할 수 있어야 함!

연산자 오버로딩을 하는데 있어서의 주의사항

  • 본래의 의도를 벗어난 형태의 연산자 오버로딩 X
  • 연산자의 우선순위와 결합성은 바뀌지 않는다.
  • 매개변수의 디폴트 값 설정이 불가능 하다.
  • 연산자의 순수기능 까지 빼앗을 수 없다.

10-2 단항 연산자의 오버로딩

전위증가와 후위증가의 구분

C++에서 전위 및 후위 연산에 대한 해석 방식
++pos -> pos.operator++();
pos++ -> pos.operator++(int);

--pos -> pos.operator--();
pos-- -> pos.opreator--(int);

관련예제
PostOpndOveraloding.cpp

#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 << ", " << ypos << "]" << endl;
	}
	Point& operator++() // 전위 증가
	{
		xpos += 1;
		ypos += 1;
		return *this;
	}
	const Point operator++(int) // 후위 증가
	{
		const Point retobj(xpos, ypos); // const Point retobj(*this);
		xpos += 1;
		ypos += 1;
		return retobj;
	}
	friend Point& operator--(Point& ref);
	friend const Point operator--(Point& ref, int);
};

Point& operator--(Point& ref) // 전위 감소
{
	ref.xpos -= 1;
	ref.ypos -= 1;
	return ref;
}

const Point operator--(Point& ref, int) // 후위감소
{
	const Point retobj(ref); // const 객체라고함
	ref.xpos -= 1;
	ref.ypos -= 1;
	return retobj;
}

int main(void)
{
	Point pos(3, 5);
	Point cpy;
	cpy = pos--;
	cpy.ShowPosition();
	pos.ShowPosition();

	cpy = pos++;
	cpy.ShowPosition();
	pos.ShowPosition();
	return 0;
}

후위 증가의 효과를 정의하기위해 operator++(int) 와 operator--(int)내의 함수에서 const를 사용하여 함수 내에서 retobj의 변경을 막겠다는 의도와 const형 임시객체를 반환하고 그 뒤에 값이 변경되는 후위증가 및 감소의 특성을 반영하였다.

위 예제와 관련한 전위 증감과 후위 증감에 대한 것
일반적으로 C++의 연산 특성은 다음과 같다.
int main(void)
{

int num = 100;

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

++(++num); // 컴파일 성공
--(--num); // 컴파일 성공

}

PostOpndOveraloding.cpp 예제에서 후위 증감함수들을 const를 사용하여 표현한 이유는 위의 특성을 반영하여 후위증감 시 const객체를 반환하지만 함수들은 증가의 경우 함수가 const함수가 아니고 감소의 경우 매개변수 참조자가 const로 선언되지 않았기 때문에 에러를 발생시킨다.


10-3 교환법칙 문제의 해결

일반적으로 연산자 오버로딩에서 pos라는 객체가 존재한다고 할시
pos x 3은 되지만 (pos.operator*(3))
3 x pos와 같이 연산을 하려면 전역함수의 형태로 곱셈 연산자를 오버로딩 하는 수 밖에 없다.

관련예제
CommuMultipleOperation.cpp

#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 << ", " << ypos << "]" << endl;
	}
	Point operator*(int times)
	{
		Point pos(xpos * times, ypos * times);
		return pos;
	}
	friend Point operator*(int times, Point& ref);
};

Point operator*(int times, Point& ref)
{
	return ref * times;
}

int main(void)
{
	Point pos(1, 2);
	Point cpy;

	cpy = 3 * pos;
	cpy.ShowPosition();

	cpy = 2 * pos * 3;
	cpy.ShowPosition();
	return 0;
}

전역함수에 Pointer operator*(int times, Point& ref)로 정의를 해주어 곱셈 연산자의 교환법칙이 성립하도록 하였다.


10-4 cout, cin 그리고 endl의 정체

cout와 endl 이해하기

ConsoleOutput.cpp

#include <iostream>
namespace mystd
{
	using namespace std;

	class ostream
	{
	public:
		void operator<< (const char* str)
		{
			printf("%s", str);
		}
		void operator<< (char* str)
		{
			printf("%c", str);
		}
		void operator<< (int num)
		{
			printf("%d", num);
		}
		void operator<< (double e)
		{
			printf("%g", e);
		}
		void operator<< (ostream& (*fp)(ostream& ostm))
		{
			fp(*this);
		}
	};

	ostream& endl(ostream& ostm)
	{
		ostm << '\n';
		fflush(stdout);
		return ostm;
	}

	ostream cout;
}

int main(void)
{
	using mystd::cout;
	using mystd::endl;

	cout << "Simple String";
	cout << endl;
	cout << 3.14;
	cout << endl;
	cout << 123;
	endl(cout);
}

예제를 실행하면 이상하게 '\n'이 원래는 공백으로 표시되어 결과가 나와야하는데 아스키 코드 값인 10이 출력이 된다... 왜 이런 현상이 발생하는 지는 모르겠다.. ---> main함수에서 using std::cout, std::endl을 사용하여 컴파일을 하면 정상적으로 작동이 된다.

<<, >> 연산자의 오버로딩

<<, >> 를 오버로딩하려면 ostream 클래스 멤버함수에 정정하거나 전역함수에 의한 방법 둘 중하나를 해야하는데 전자는 불가능하므로 전역함수를 사용하는 방법을 선택!

PointConsoleOutput.cpp

#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 << ", " << ypos << ']' << endl;
	}
	friend ostream& operator<< (ostream&, const Point&);
};

ostream& operator<<(ostream& os, const Point& pos)
{
	os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
	return os;
}

int main(void)
{
	Point pos1(1, 3);
	cout << pos1;
	Point pos2(101, 303);
	cout << pos2;
	return 0;
}

cout가 ostream의 클래스 객체이고 인자로 ostream형 객체와 Point 참조형을 받아 다음과 같이 함수를 구성하면 된다.

profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글

관련 채용 정보