본문 바로가기

C++

C++ 연산자 오버로딩(Operator Overloading)

연산자 오버 로딩이란
하나의 연산자가 오버 로딩을 통해서 기존에 존재하던 연산자의 기본 기능 이외에 다른 기능을 추가하는 것

 

연산자 오버 로딩 사용법

class Valueclass
{
private:
	int num1, num2;
public:
	Valueclass(int num1, int num2) : num1(num1), num2(num2) {}

	void Paint()
	{
		cout << "num1 : " << num1 << endl << "num2 : " << num2 << endl;
	}
	Valueclass operator+(Valueclass& ref)
	{
		return Valueclass(num1 + ref.num1, num2 + ref.num2);
	}

};

void main()
{
	Valueclass va1(10, 20);
	Valueclass va2(20, 30);
	Valueclass va3 = va1 + va2;
	va3.Paint();
}

Valueclass를 서로 더해주는 기능의 +연산자는 원래 존재하지 않는다.
하지만 Valueclass opertor+라는 연산자 오버 로딩을 이용하여 +연산자의 Valueclass를 서로 더해주는 기능이 생겼다.
연산자 오버 로딩을 사용할 때 매개변수에 들어가는 값은 va2가 들어가게 된다.
컴퓨터에서 컴파일 할 때는 저 부분을 va1.operator+(va2)로 읽기 때문이다.

 

class Valueclass
{
private:
	int num1, num2;
public:
	Valueclass(int num1, int num2) : num1(num1), num2(num2) {}

	void Paint()
	{
		cout << "num1 : " << num1 << endl << "num2 : " << num2 << endl;
	}
	Valueclass operator+(int value)
	{
		return Valueclass(num1 + value, num2 + value);
	}

};

void main()
{
	Valueclass va1(10, 20);
	Valueclass va2(20, 30);
	Valueclass va3 = va1 + 10;
	va3.Paint();
}

연산자 오버 로딩은 자료형이 다른 피연산자를 넣어도 동일하게 작용한다.
하지만 저런 식으로 사용할 때 주의점이 존재하는데
10 + va1; 이렇게 사용하면 에러가 발생 하합니다. 이유는 10에는 Valueclass를 받아와 10 더해주는 연산자 오버 로딩
기능이 존재하지 않기 때문입니다.

 

전역 함수에 의한 연산자 오버 로딩
멤버 함수에 의한 연산자 오버 로딩의 경우에는 va1.poerator+(va2)의 방식으로 연산되었다면
전역 함수에 경우에는 opertor+(va1, va2)라는 결과로 연산이 된다.
참고로 동일한 자료형을 대상으로 + 연산자를 전역 함수 기반으로, 그리고 멤버 함수 기반으로 동시에 오버 로딩 할 경우,
멤버 함수 기반으로 오버 로딩 된 함수가 전역 함수 기반으로 오버 로딩 된 함수보다 우선시 되어 호출된다.
그렇기 때문에 가급적 이런 상황을 만들지 않는 게 좋다.

class Valueclass
{
private:
	int num1, num2;
public:
	Valueclass(int num1, int num2) : num1(num1), num2(num2) {}

	void Paint()
	{
		cout << "num1 : " << num1 << endl << "num2 : " << num2 << endl;
	}
	friend Valueclass operator+(const Valueclass& va1, const Valueclass& va2);
};

Valueclass operator+(const Valueclass& va1, const Valueclass& va2)
{
	Valueclass temp(va1.num1 + va2.num1, va1.num2 + va2.num2);
	return temp;
}

void main()
{
	Valueclass va1(10, 20);
	Valueclass va2(20, 30);
	Valueclass va3 = va1 + va2;

	va3.Paint();
}

위의 예제는 전역 함수 기반의 연산자 오버 로딩에 대한 일반적인 모습이다.

 

단항 연산자의 오버 로딩

class Valueclass
{
private:
	int num1, num2;
public:
	Valueclass() {}
	Valueclass(int num1, int num2) : num1(num1), num2(num2) {}

	void Paint()
	{
		cout << "num1 : " << num1 << endl << "num2 : " << num2 << endl;
	}
	Valueclass operator++()
	{
		num1 += 1;
		num2 += 1;
		return *this;
	}
	Valueclass operator++(int)
	{
		Valueclass temp(*this);
		num1 += 1;
		num2 += 1;
		return temp;
	}
};

void main()
{
	Valueclass va1(10, 20);
	Valueclass va2;
	va2 = va1++;
	va2.Paint();
	va1.Paint();
	cout << "-----------------------------" << endl;
	va2 = ++va1;
	va2.Paint();
	va1.Paint();
}

num1과 num2를 1씩 올려주는 단항 연산자를 만들었다.
첫 번째 단항 연산자의 경우
num1과 num2에 1을 더한 뒤 *this를 반환한다. *this는 this가 가리키는 주소의 실질적인 데이터를 의미한다.
즉 자기 자신 의 값을 1씩 올리고 리턴해주는 연산자이다.
두 번째 단항 연산자는 첫 번째 와 다르게 일단 매개변수로 int 타입이 등장하는데
이는 c++에서 전위 또 흔 후위 연산에 대한 구분 규칙에 의한 것이다.
안에 내용으로는 자기 자신을 temp라는 변수로 만들어 둔 다음에 자기 사진의 값을 올리고 temp를 반환한다.
그렇기 때문에 자기 자신의 값을 증가했지만 실제 반환하는 값을 증가되지 않는다.

 

대입 연산자의 오버 로딩

대입연사자는 객체의 값을 그대로 복사해서 넘겨주는 기능을하는데 class = class로 작동한다.

위에 연산자 오버로딩은 만들어주지 않으면 컴파일 에러를 출력했지만 대입연산자는 다르다.

대입연산자를 구현하지 않고 대입연산을 시도하면 문제가없이 컴파일이된다.

그 이유는 대입연산자를 구현하지 않으면 컴파일러는 자동적으로 디폴트 대입연산자를 생성하기 때문이다.

첫번째 예제의 Valueclass va3 = va1 + va2;은 va3.operator=(va1.operator+(va2));라고 보면된다.

저기서 operator=은 구현하지 않았지만 문제없음을 확인할수있다.

근데 디폴트 대입 연산자의 문제가있다. 그건바로 얉은 복사를 한다. 그렇기 때문에

깊은 복사가 필요한경우에는 사용자가 직접 연산자 오버로딩을 해야한다.

class Valueclass
{
private:
	char* str;
public:
	Valueclass(char* str);
	~Valueclass();
	Valueclass(Valueclass& va1);
	void Paint()
	{
		cout << "str : " << str << endl;
	}
	Valueclass operator=(Valueclass& va1)
	{
		this->str = new char[strlen(str)];
		strcpy_s(this->str, strlen(str), str);
		return *this;
	}
};

Valueclass::Valueclass(char* str)
{
	this->str = new char[strlen(str)];
	strcpy_s(this->str, strlen(str), str);
}

Valueclass::~Valueclass()
{
	delete[](str);
}

Valueclass::Valueclass(Valueclass& va1)
{
	this->str = new char[strlen(str)];
	strcpy_s(this->str, strlen(str), str);
}


void main()
{
	Valueclass va1("슬깃");
	Valueclass va3 = va1;

	va3.Paint();
}

 

 

오버로딩이 불가능한 연산자의 종류

. 맴버 접근 연산자
.* 맴버 포인터 연산자
:: 범위 지정 연산자
?: 조건 연산자
sizeof 바이트 단위 크기 계산
typeid RTTI관련 연산자
static_cast 형변환 연산자
dynamic_cast 형변환 연산자
const_cast 형변환 연산자
reinterpret_cast 형변환 연산자

'C++' 카테고리의 다른 글

C++ 함수포인터  (0) 2020.09.07
C++ 연산자 오버로딩 주의사항  (0) 2020.09.06
C 파일입출력  (0) 2020.09.04
C++ malloc,callco,new  (0) 2020.09.01
C++ 문자열 함수  (0) 2020.08.31