연산자 오버로딩

falseman_go·2022년 5월 7일
0

R&D-Language

목록 보기
9/24

연산자 오버로딩

연산자 오버로딩이란 지난 시간에 함수의 이름을 재사용하는 함수의 오버로딩처럼 연산자를 사용하는 방법을 오버로딩하여 새로운 연산방법을 만드는 것이다. 아래의 코드를 보자

// 클래스
class Position {
public:
	int _x;
	int _y;

	Position() {
		_x = 0;
		_y = 0;
	}
};

// 메인 함수
int main() {
	Position pos1;
	Position pos2;

	pos1._x = 1;
	pos1._y = 1;

	pos2._x = 2;
	pos2._y = 2;

	Position pos3 = pos1 + pos2;

	cout << "계산된 X 좌표 : " << pos3._x << " / 계산된 Y 좌표 : " << pos3._y << endl;
}

이 코드는 2D좌표계의 위치에 대한 정보를 갖는 객체의 설계도이다. X값과 Y값을 멤버 변수로 가지고 있으며, 기본 생성자는 이 둘을 원점으로 초기화 시켜준다. 메인 함수에서는 이 클래스를 가지고 좌표 값을 갖는 객체를 만들어 두 개의 객체에 값을 다르게 준 뒤에 더하고 있다. 평범하게 생각하면 pos1과 pos2의 X와 Y값이 각각 더해질 것처럼 생각되지만 실제로는 에러가 발생한다. 연산자 +에는 클래스 Position을 더하는 함수가 없기 때문인데, 이때 연산자 오버로딩으로 Position 타입의 +연산 함수를 만들어주면 된다. 연산자 오버로딩 함수의 형식은 아래와 같다.

타입 operator부호(매개 변수)

operator 키워드 앞에 연산할 부호가 붙는 것을 유의하여 작성해야 한다.

// 클래스 안의 멤버 함수로 작성
	Position operator+(const Position& arg) {
		Position pos;

		pos._x = _x + arg._x;
		pos._y = _y + arg._y;

		return pos;
	}

타입은 클래스이고, 좌표끼리 더하는 의미의 +연산자를 오버로딩하고 있다. 매개변수로는 더하려고 하는 같은 타입의 변수가 들어있는데 참조형식이며 const 키워드로 수정할 수 없게 막았다. 또 원본 값인 pos1의 객체를 리턴하는 것이 아니라 새로운 객체를 생성하여 값을 더하고 리턴하여 각각의 피연산자의 데이터가 수정되는 일이 없게 하였다.

Position pos3 = pos

그리하여 pos3에는 각 좌표를 더한 pos가 대입되게 되는데 형식이 지난 시간에 정리했던 복사 생성자와 같아졌다.

연산자 오버로딩 함수의 종류

이 오버로딩 함수는 앞서 만들었던 함수처럼 클래스 내의 멤버 함수로 만들 수 있고, 전역 함수로도 만들 수 있다. 각각의 함수는 다른 특징을 보이고 있다.

멤버 함수
1) a oper b의 형태에서 왼쪽을 기준으로만 실행이 된다.
2) a가 클래스여야 가능하며 a를 기준 피연산자라고 한다.
3) a가 클래스가 아니라면 사용할 수 없다.
전역함수
1) a oper b의 형태에서 a와 b 모두 연산자 함수의 피연산자로 만들어준다.
2) a가 클래스가 아니어도 사용이 가능하다.

다음은 전역 함수로 만든 연산자 오버로딩 함수이다.

// a가 클래스 타입이 아닌 정수형인 것을 확인.
Position operator+(int a, const Position& b) {
	Position ret;

	ret._x = b._x + a;
	ret._y = b._y + a;

	return ret;
}

// pos4를 추가한 메인 함수
int main() {
	Position pos1;
	Position pos2;

	pos1._x = 1;
	pos1._y = 1;

	pos2._x = 2;
	pos2._y = 2;

	Position pos3 = pos1 + pos2;
    // 앞에 피연산자가 클래스 타입이 아닌 정수형
	Position pos4 = 1 + pos3;


	cout << "계산된 X 좌표 : " << pos3._x << " / 계산된 Y 좌표 : " << pos3._y << endl;
	cout << "계산된 X 좌표 : " << pos4._x << " / 계산된 Y 좌표 : " << pos4._y << endl;
}

이렇게 클래스에 맞추어 연산자 오버로딩을 하면 상황에 따라 적절하게 원하는 연산을 만들어 낼 수 있다. 하지만 오버로드가 불가능한 부호도 있는데 인터넷 검색을 통해 알아보니 다음 부호들은 연산자 오버로딩이 불가능한 부호란 것을 알았다.

연산자기능
.멤버 선택
.*멤버 포인터 선택
::범위
?:조건
#문자열 전처리기 변환
#전처리기 연결

이밖에도 특수한 상황은 존재한다. 보통 연산을 수행하면 연산자와 2개의 피연산자가 존재한다고 생각하는데, 전위 혹은 후위 증감 연산자는 피연산자가 1개만 존재한다. 증감 연산자도 연산자 오버로딩을 사용하여 만들 수 있는데 방식이 다른 함수들과는 특이한 부분이 있다.

// 전위 증감
	Position& operator++() {
		_x++;
		_y++;

		return *this;
	}

// 후위 증감
	Position operator++(int) {
		Position ret = *this;

		_x++;
		_y++;

		return ret;
	}

++연산자가 앞에 붙는지, 뒤에 붙는지 구분하기 위해 매개변수에 데이터 타입을 하나 넣어준다.

profile
정리하는 블로그

0개의 댓글