[C++] 연산자를 커스텀해보자(operator overloading)

2022. 7. 3. 12:22♣ C++

이번 포스팅에선 연산자 오버로딩에 대해 알아보겠습니다.

연산자: 말그대로 더하기, 빼기, 곱하기 등의 연산을 하는 실행 코드.

오버로딩: 같은 이름을 쓰지만 매개 변수에 따라 다른 실행을 할 수 있게 하는 규칙.

연산자 오버로딩은 즉, 기존의 연산자 실행과 더불어 사용자가 마음대로 커스텀하여 연산자를 사용할 수 있도록 하는 것을 말한다.

 

개발 환경 : VSCode, Windows 10

 

 

 

 

Contents

📌 연산자 오버로딩 & 연산자 함수 정의

📌 오버로딩의 제약 사항

 

 

 

 

기본 개발 세팅은 다음과 같습니다.

#include <iostream>
#include <string.h>
#include <string>
using namespace std;

int main()
{
	return 0;
}

 

 

 

 

 

📌 연산자 오버로딩 & 연산자 함수 정의


연산자 오버로딩이란?

-, *, +, / 등의 연산자에 대해서 사용자 마음대로 커스텀하여 사용할 수 있는 것을 말합니다.

사용자 정의 타입까지 확장할 수 있으며, 클래스도 하나의 타입임을 보여줍니다.

 

 

 

📍 연산자 함수

연산자를 오버로딩하기 위해선 함수처럼 정의해야 합니다. 마음대로 costom 해서 함수처럼 사용하면 됩니다.

// 연산자 함수 원형
반환타입 operator오버로딩할연산자(매개변수목록);

 

// 연산자 함수 정의
반환타입 클래스이름::operator오버로딩할연산자(인수 목록)
{
	return 내용;
}

 

 

 

 

 

(1) 클래스의 멤버 함수로 정의하는 방법

 

Average 클래스를 정의합니다. x, y 값을 매개 변수로 삼습니다.

class Average
{
	private:
		double x_;
		double y_;
	
	public:
		Average(double x_, double y_);
		Average operator-(const Average& other);
};

Average operator-(const Average& other);

빼기 연산자를 오버로딩했습니다.

 

 

다음은 연산자 함수와 생성자를 정의한 것입니다.

Average Average::operator-(const Average& other)
{
	return Average((x_ + other.x_)/2,(y_ + other.y_)/2);
}

Average::Average(double x_, double y_)
{
	x_ = x_;
	y_ = y_;
}

void Average::Display()
{
	cout << "x, y의 좌표: " << x_ << "," << y_ << endl;
}

빼기 연산자를 두 좌표의 중간 지점을 구하는 것으로 커스텀했습니다.

연산자 함수 정의도 멤버 함수를 정의하는 것과 거의 유사합니다.

 

 

main() 함수입니다.

int main()
{
	// 1
	Average me = Average(5, 7);
	Average you = Average(4.4, 7.7);
	Average me_you = me - you;
	me_you.Display();
	return 0;
}

 

결과

x, y의 좌표: 8.0082e-307,8.00991e-307

 

 

 

 

(2) 전역 함수로 정의하는 방법

전역 함수로 정의할 경우, 클래스와 관련성이 없기에 private에 접근하지 못합니다. OOP의 캡슐화를 구현한 friend 함수를 사용하면 private에 접근할 수 있습니다.

 

먼저 friend 함수가 아닌 일반 전역 함수로 정의했습니다. 함수 밖 어디에 정의해도 상관없습니다.

Average operator+(const Average& var1, const Average& var2);

 

 

더하기 연산자를 커스텀했으며, 둘의 좌표를 더하고 2를 곱하는 실행으로 설정했습니다.

Average operator+(const Average& var1, const Average& var2)
{
	return Average((var1.x_ + var2.x_)*2, (var1.y_ + var2.y_)*2)
}

 

 

main() 함수입니다. 과연 함수가 제대로 실행되었을까요?

int main()
{
	Average me = Average(5, 7);
	Average you = Average(4.4, 7.7);
	Average me_you = me + you;
	me_you.Display();
	return 0;
}

 

결과

error: 'double Average::x_' is private within this context

역시나 private에는 접근이 안된다는 오류가 컴파일 중 발생했습니다.

 

 

 

 

다시 friend 전역 함수로 정의합니다. 즉, 연산자 함수를 밖에 정의하고, 해당 class 안에 friend 연산자 함수를 또 정의해주는 것을 말합니다. 

class Average
{
	private:
		double x_;
		double y_;
	
	public:
		Average(double x_, double y_);
		Average operator-(const Average& other);
		friend Average operator+(const Average& var1, const Average& var2);
		void Display();
};

Average operator+(const Average& var1, const Average& var2);

class 안에 friend 연산자 함수 원형을 정의해줬습니다.

 

 

결과

x, y의 좌표: 8.0082e-307,8.00991e-307

깔__끔

 

 

 

 

 

 

📌 오버로딩의 제약 사항


오버로딩 시 몇가지 제약 사항이 있습니다.

 

(1) 전혀 새로운 연산자를 정의할 순 없습니다.

=> %%를 나눗셈 연산자로 정의하겠어!

 

(2) 디폴트 인수를 사용할 수 없습니다.

 

(3) 기본 타입을 다루는 연산자의 의미는 재정의할 수 없습니다.

=> 덧셈 연산자가 뺄셈 수행하도록 오버로딩

 

(4) 오버로딩되는 연산자는 기본 타입에 적용되는 피연산자의 수, 우선순위 및 그룹화를 준수해야 합니다.

=> 나눗셈 연산자는 이항 연산자. 단항 연산자로 다룰 수 없습니다.

 

 

 

 

 

[오버로딩할 수 없는 연산자]

다음 연산자들은 오버로딩할 수 없습니다.

 

:: 범위 지정 연산자
. 멤버 연산자
.* 멤버 포인터 연산자
? : 삼항 조건 연산자
sizeof 크기 연산자
typeid 타입 인식
const_cast 상수 타입 변환
dynamic_cast 동적 타입 변환
reinterpret_cast 재해석 타입 변환
static_cast 정적 타입 변환

 

 

 

 

[멤버 함수로만 오버로딩할 수 있는 연산자]

전역 함수가 아닌 멤버 함수로만 오버로딩할 수 있습니다.

 

= 대입 연산자
() 함수 호출 
[] 배열 인덱스
-> 멤버 접근 연산자

 

 

 

 

 

지금까지 연산자 오버로딩에 대해 살펴보았습니다.

고생하셨습니다.