본문 바로가기
프로그래밍/C++

연산자 오버로딩(operator overlonding)(2)

by 리뷰하는 (게임)프로그래머_리프TV 2010. 4. 4.



연산자 오버로딩에 대해 알아 보았다, 하지만 아직 연산자 오버로딩에 대해 완벽하게 알고 있는 것 같진 않다.


void main()
{
	Point p1(1, 2);
	// p1.operator(10);
	p1 + 10;
	p1.ShowPoint();
	// 10.operator(p1);
	10 + p1;
	// 과연 이게 우리가 원하는 오버로딩인가?
	p1.ShowPoint();
	// 값 또한 바뀌지 않았다.
}
// 결과
// 11 12
// 11 12​


그렇다면 저 구문에 대해서 실행을 해주고 싶다면 어떻게 해야 할까?
이런 부분에 대해서는 전역으로 연산자 오버로딩을 해 주어야 한다.

class Point
{
...
public:
	friend void operator+( int val, Point& p );
}

void operator+( int val, Point& p )
{
	// 단순히 자리만 변경하여 사용해 주면 된다.
	p+val;
}

void main()
{
	Point p1(1, 2);
	// p1.operator(10);
	p1 + 10;
	p1.ShowPoint();
	// 10.operator(p1);
	10 + p1;
	// 이제는 사용이 가능하게 바뀌었다.
	p1.ShowPoint();
	// 값의 변경이 일어 난 것을 확인 할 수 있다.
}
// 결과
// 11 12
// 21 22​



다음은 [] 연산자에 대해서 연산자 오버로딩을 해보자.

#include <iostream>

class AAA
{
	int idx;
	int arr[5];
public:
	AAA():idx(0){}
	void AddArr( int n )
	{
		arr[idx++] = n;
	}
	void ShowAllData()
	{
		for( int i=0; i<idx; i++ )
			std::cout << arr[i] << std::endl;
	}
	// [] 연산자를 오버로딩 하여 값을 받고 있다.
	int& operator[](int i)
	{
		idx++;
		// arr[i]를 리턴하여 그 값에 대해 숫자를 삽입한다고 볼 수 있다.
		return arr[i];
	}
};

void main()
{
	AAA a;
	// a.operarot[](0) = 1;
	a[0] = 1;
	// a.operarot[](1) = 2;
	a[1] = 2;
	a[2] = 3;
	a[3] = 4;
	a[4] = 5;
	//a.AddArr(1);
	//a.AddArr(2);
	//a.AddArr(3);
	//a.AddArr(4);
	//a.AddArr(5);
	a.ShowAllData();
}
// 결과
// 1
// 2
// 3
// 4
// 5​


비슷한 내용이지만 이번엔 int가 아닌 객체를 직접 저장하는 배열이 존재한다고 하고,
조금 소스를 변경해 보자.

#include <iostream>

// 배열에 들어 가게될 AAA 클래스
class AAA
{
	int x;
	int y;
public:
	// 디폴트 매개변수를 사용해 AAAArr에서 배열 선언이 가능하게 변경
	AAA( int _x=0, int _y=0 ) : x(_x), y(_y){}
	// 원활한 출력을 위해 << 연산자를 오버로딩 하였다.
	friend std::ostream& operator <<(std::ostream& os, const AAA& p );
};

// 화면에 출력을 맞게 된다.
std::ostream& operator <<(std::ostream& os, const AAA& p )
{
	os << "[" << p.x << ", " << p.y << "]";
	return os;
}

class AAAArr
{
	int idx;
	// AAA 객체를 담을 객체 배열
	AAA arr[5];
public:
	AAAArr() : idx(0){}
	void ShowAllData()
	{
		for( int i=0; i<idx; i++ )
			std::cout << arr[i] << std::endl;
	}
	// [] 연산자를 오버로딩 하여 값을 받고 있다.
	AAA& operator[](int i)
	{
		idx++;
		// arr[i]를 리턴하여 그 값에 대해 숫자를 삽입한다고 볼 수 있다.
		return arr[i];
	}
};

void main()
{
	AAAArr a;

	// 임시 객체를 선언해 값을 삽입
	a[0] = AAA(10, 20);
	a[1] = AAA(11, 21);
	a[2] = AAA(12, 22);
	a[3] = AAA(13, 23);
	a[4] = AAA(14, 24);

	// 화면에 출력한다.
	a.ShowAllData();
}
// 결과
// [10, 20]
// [11, 21]
// [12, 22]
// [13, 23]
// [14, 24]​


조금 길게 느껴질 수도 있겠지만 큰 틀은 비슷하다.
단지 객체를 담기 위한 클래스와,
배열 안에 들어갈 클래스를 나눈것 뿐이다.
스스로가 스스로를 담기 위해선,
*를 통해서 해야 될 것으로 생각된다.

다음은 대입 연산자(=)를 오버로딩 하는 것에 대해서 살펴 보자.
실제로 연산자 오버로딩이 이루어진 곳에,
p1=p2;
를 하게 되면 p2에 값이 p1으로 이동 된 것을 알 수 있는데,
실제로 이것은 디폴트 대입 연산자 오버로딩? 정도로 표현 할 수 있을 것이다.

#include <iostream>

class Point
{
	int x;
	int y;
public:
	Point( int _x=0, int _y=0 ) : x(_x), y(_y){}
	Point& operator+( const Point& p )
	{
		x = x+p.x;
		y = y+p.y;
		return *this;
	}
	// 선언해 주지 않아도 자동으로 생성되는 디폴트 대입 연산자
	//Point& operator=( const Point& p )
	//{
	//	x = p.x;
	//	y = p.y;
	//	return *this;
	//}
	void ShowData()
	{
		std::cout << x << " " << y << std::endl;
	}
};

void main()
{
	Point a(1, 1);
	Point b(10,10);
	a+b;

	a.ShowData();
	b.ShowData();

	// 디폴트 대입 연산자가 발동하였다.
	a = b;

	// 값의 변경이 일어 난 것이 확인 가능.
	a.ShowData();
}
// 결과
// 11 11
// 10 10
// 10 10​


어찌 보면 복사 생성자와 같은 맥락이지만,
당연히 기본적인 디폴트 대입 연산자는 얕은 복사가 이루어 진다.
무슨 의미인지 알겠는가?
완벽하게 해주기 위해선,
깊은 복사가 이루어 져야 한다는 것이다.

#include <iostream>
#include <string.h>

class Point
{
	char* name;
public:
	Point( char* _name )
	{
		name = new char[strlen(_name)+1];
		strcpy( name, _name );
	}
	~Point()
	{
		delete name;
	}
	// 선언해 주지 않아도 자동으로 생성되는 디폴트 대입 연산자
	Point& operator=( const Point& p )
	{
		// 얕은 복사가 이루어 지면 안되기 때문에
		// 깊은 복사가 이루어지게 변경해 주어야 한다.
		name = new char[strlen(p.name)+1];
		strcpy( name, p.name );
		return *this;
	}
	void ShowName()
	{
		std::cout << name << std::endl;
	}
};

void main()
{
	Point a("nameA");
	Point b("nameB");

	a.ShowName();
	b.ShowName();

	a = b;

	a.ShowName();
}
// 결과
// nameA
// nameB
// nameB​

'프로그래밍 > C++' 카테고리의 다른 글

템플릿(template)  (0) 2010.04.04
임시 객체 생성  (0) 2010.04.04
연산자 오버로딩(operator overloading)(1)  (0) 2010.04.04
가상 복사 생성자  (0) 2010.04.03
virtual(가상)  (0) 2010.04.03