연산자 오버로딩(overloading)

·2022년 5월 27일
0

cpp_study

목록 보기
8/25

(여담) 친한 동기가 퇴사를 했다.. 슬프다.

연산자 오버로딩은 실무에서 크게 쓰이지 않는데다가, 우선순위상 상대적으로 밀린다.
따라서 이번 연산자 오버로딩은 블로그에서 상세하게 다루는 것보다는 그냥 적당히 나중에 검색을 위한 정도로 작성하려고 한다.

자주 사용하는 씹어먹는 C++ 책보다 아래 글이 더 짧고 참고하기 좋아보여서 첨부한다.

참고하기: https://blog.hexabrain.net/177

주의) 몇몇 연산자 오버로딩은 전역 함수 오버로딩이 안되고, 멤버 함수 오버로딩만 가능할 수 있음.

1. 연산자 오버로딩(Operator Overloading)

(리턴 타입) operator(연산자) (연산자가 받는 인자)

연산자 오버로딩은 보통 객체.operator@(피연산자) 의 형식으로 사용된다.
아래 코드를 참고해서 보면, 객체 <- (NUMBOX), 피연산자 <- (NUMBOX 또는 int 자료형) 변수 이렇게 될 수 있다.

#include <iostream>
 
using namespace std;
 
class NUMBOX
{
private:
	int num1, num2;
public:
	NUMBOX(int num1, int num2) : num1(num1), num2(num2) { }
	void ShowNumber() 
	{
		cout << "num1: " << num1 << ", num2: " << num2 << endl;
	}
	NUMBOX operator+(NUMBOX &ref)
	{
		return NUMBOX(num1+ref.num1, num2+ref.num2);
	}
	
	NUMBOX operator+(int x)
	{
		return NUMBOX(num1+x, num2+x);
	}
};
 
int main()
{
	NUMBOX nb1(10, 20);
	NUMBOX nb2(5, 2);
	NUMBOX result = nb1 + nb2;
	NUMBOX result2 = nb1 + 2;
 
	nb1.ShowNumber();
	nb2.ShowNumber();
	result.ShowNumber();
	result2.ShowNumber();
}

그런데, 객체 + 피연산자 형태가 아니라 피연산자 + 객체 형태가 되는 경우
피연산자.operator@(객체)로 컴파일되기 때문에 에러가 발생하게 된다.
이때 friend 키워드를 써서 전역 함수 오버로딩을 하면 해결이 된다.

2. 전역 함수 오버로딩

객체 함수 오버로딩과 달리, 전역 함수 오버로딩은

피연산자 + 피연산자 = operator+(피연산자, 피연산자)

이렇게 생겨 먹은 연산자 오버로딩으로, 연산자 앞에 피연산자가 들어갈 수 있는 효과가 있다.

아래는 예제 코드이다.

#include <iostream>
 
using namespace std;
 
class NUMBOX
{
private:
	int num1, num2;
public:
	NUMBOX(int num1, int num2) : num1(num1), num2(num2) { }
	void ShowNumber() 
	{
		cout << "num1: " << num1 << ", num2: " << num2 << endl;
	}
	NUMBOX operator+(NUMBOX &ref)
	{
		return NUMBOX(num1+ref.num1, num2+ref.num2);
	}
	
	NUMBOX operator+(int x)
	{
		return NUMBOX(num1+x, num2+x);
	}
	
	friend NUMBOX operator+(int x, NUMBOX &ref);
};

NUMBOX operator+(int x, NUMBOX &ref){
    return NUMBOX(ref.num1 + x, ref.num2 + x);
}
 
int main()
{
	NUMBOX nb1(10, 20);
	NUMBOX nb2(5, 2);
	NUMBOX result = nb1 + nb2;
	NUMBOX result2 = nb1 + 2;
	
	NUMBOX result3 = 2 + nb2;
 
	nb1.ShowNumber();
	nb2.ShowNumber();
	result.ShowNumber();
	result2.ShowNumber();
	result3.ShowNumber();

}

friend 키워드

참고하기

friend 클래스와 friend 함수가 있는데,
A 클래스의 friend인 B 클래스는 A 클래스의 private 및 protected 멤버에 접근할 수 있음.
A 클래스의 friend 함수는 A 클래스의 private 및 protected 멤버 함수에 접근이 가능함.

3. 단항 연산자 오버로딩

전위 후위 연산자는 아래와 같이 구분됨
💥 단항 연산자 오버로딩은 멤버 함수로만 오버로딩하는 게 좋음.

++nb = nb.operator++(); // 전위 증가 연산
nb++ = nb.operator++(int); // 후위 증가 연산

4. 대입 연산자 오버로딩

대입 연산자가 정의되지 않으면 디폴트 대입 연산자가 삽입이 됨
멤버 vs 멤버 복사를 수행할 때 깊은 복사가 아닌 얕은 복사를 진행함

-> delete를 통해 소멸할 때 중복 소멸하는 문제 및 기존 문자열 접근, 소멸도 불가능해지는 상황이 발생

=> 디폴트 대입 연산자 때문에 발생하는 얕은 복사 대신 대입 연산자 오버로딩으로 깊은 복사 정의하기

Student& operator=(Student& ref)
{
	delete []name;
	name = new char[10];
	strcpy(name, ref.name);
	age = ref.age;
	return *this;
}

추가) 첨자 연산자

char& operator[](const int index);

레퍼런스를 리턴하며(해당하는 변수의 값을 바꿔야 할 수도 있기 때문),
사용될 때는 대강 str[index] = 'c' 이렇게 쓰인다.

profile
이것저것 개발하는 것 좋아하지만 서버 개발이 제일 좋더라구요..

0개의 댓글