[C++] 연산자 오버로딩

2024. 4. 2. 08:10Programming Language/C++

클래스는 내가 선언한 자료형이기 때문에 컴파일러는 연산을 어떻게 처리해야 할지 알 수가 없다.

이때 연산자 오버로딩을 사용하여 정의하면 내가 만든 자료형끼리의 연산이 가능해진다.

연산자 오버로딩 (Operator Overloading)

• 오버로딩 : 동일한 이름의 함수이지만 인자나 몇 가지 특징이 달라서 컴파일러가 충분히 구별할 수 있는 것
• 기존에 정의된 연산자(`+`, `-`, `*`, `=` 등)처럼 각 연산자에 대응하는 기능을 직접 정의해서 만든다.

이를 통해 사용자가 정의한 자료형도 원래 자료형처럼 연산자를 사용할 수 있다.

• `operator` 키워드를 사용하고, 연산자도 함수의 일종으로 본다.

즉, 연산자를 호출했을 때 어떤 함수가 호출되도록 연결지어주는 기능이 있어야 한다.

• 클래스의 객체에 대입 연산자 `=`를 사용할 때 호출되는 함수이다.

대입 연산자 `=`의 경우 내가 `operator =`를 만들지 않아도 컴파일러가 자동으로 기본 대입 연산자를 제공해주지만, 그외에는 내가 직접 만들어야 한다.

• 보통 함수는 `함수명.`으로 호출하지만, operator 멤버 함수는 연산자가 호출됐을 때 호출된다.
• 클래스에서의 연산자 오버로딩은 내가 만든 클래스의 연산자가 호출됐을 때 실행할 기능을 추가하는 것이다.

▷ 연산자 오버로딩 예시 (대입 연산자, 덧셈 연산자)

class CMy
{
public:
	int m_i;
	float m_f;
		
	// 연산자 오버로딩 - 대입 연산자 (작성하지 않아도 컴파일러가 기본 대입 연산자를 만들어준다.)
		// 대입을 시킬 때 대입시킬 변수(c2)의 원본이 수정되어선 안 되기 때문에 추가 인자는 const 래퍼런스이다.
	CMy& operator=(const CMy& _Other)  // _Other은 호출한 객체의 추가 인자이고 대입시킬 변수(c2)이다.
	{
		m_i = _Other.m_i;  //this->m_i = _Other.m_i;  // this는 생략되어있지만 대입을 당할 변수(c3) 객체의 주소가 this에 전달된다.
		m_f = _Other.m_f;  //this->m_f = _Other.m_f;

		return *this;
	}
    
    // 연산자 오버로딩 - 덧셈 연산자
    	// 각자 멤버를 합산하는 의미로 사용
    CMy operator+(const CMy& _Other) const {  // 메서드 끝에 const는 이 연산자가 현재 객체(this)를 수정하지 않음을 나타낸다.
        CMy result;
        
        result.m_i = this->m_i + _Other.m_i;
        result.m_f = this->m_f + _Other.m_f;
        
        return result;
    }

public:
	CMy()
		: m_i(100)
		, m_f(0.5f)
	{

	}

	~CMy()
	{

	}
};

int main()
{
	// 내가 만든 자료형의 객체끼리의 대입
	c3 = c2;  // 여기에 중단점 걸어놓고 F11 누르면 위에 대입 연산자 함수 부분으로 넘어간다.
	// c3가 대입 연산자를 호출한 객체이다.
	// 즉, CMy& operator =(const CMy& _Other)의 m_i, m_f는 c3이고, _Other에 해당하는 c2를 참조받는다.
	// c2의 m_i, m_f를 c3의 멤버에 복사시키고 함수를 operator 멤버 함수를 종료시킨다.
	
    // 내가 만든 자료형의 객체끼리의 덧셈
    c3 + c2;
    // operator +를 구현하지 않은 상태에서 객체끼리 더하려고 덧셈 연산자를 사용하면 오류가 발생한다.
    	// 기본 자료형이 아니라 내가 만든 자료형이기 때문에 컴파일러가 뭘 하는건지 알 수 없기 때문이다.

	c = c2 = c3;  // m_i = 100, m_f = 0.500000000
	// 만약 대입 연산자 함수가 void 타입이라면 오류가 발생한다.
		// c3가 c2쪽으로 대입 연산자를 호출하고 나서 반환되는 것이 없다.
		// c2 = c3; 연산이 끝나면 c = ;가 된다.
		// operator 대입 연산자로 호출할 객체는 c인데 참조돼서 입력될 부분이 없다.
	// 그래서 대입 연산자를 호출시킬 객체 본인을 그대로 참조해서 원본 자체를 줘야 한다.
	// return *this;인 이유가 해당 원본 객체를 참조해서 리턴하기 때문이다.
	// 위의 경우 c2를 참조해서 되돌려준다.
		// c = c2 = c3;를 연산하고 나면 c = c2;가 된다.

	return 0;
}