※ firend의 개념을 모른다면 다음 포스팅을 먼저 숙지할 것.
연산자 오버로딩
- 사용자 정의 자료형(클래스)에 연산자를 재정의한다.
- operator 키워드와 연산자를 묶어서 함수이름을 정의하면 연산자 오버로딩이 이루어진다.
- 예 : class operator+(const class& ref)
- 연산자 오버로딩은 멤버함수에 의한 연산자 오버로딩, 전역함수에 의한 연산자 오버로딩이 있다.
- 멤버함수 연산자 오버로딩 : class.operator+(class)
- 전역함수 연산자 오버로딩 : class.operator+(class, class)
- 멤버함수, 전역함수 연산자 오버로딩 예제
#include <iostream>
using namespace std;
class OverloadingOP
{
private:
int m_iNum1, m_iNum2;
public:
OverloadingOP(int n1 = 0, int n2 = 0) : m_iNum1(n1), m_iNum2(n2) { }
void ShowMember()
{
cout << m_iNum1 << " / " << m_iNum2 << endl;
}
//멤버함수 연산자 오버로딩
OverloadingOP operator+(const OverloadingOP& ref)
{
return OverloadingOP(m_iNum1 + ref.m_iNum1, m_iNum2 + ref.m_iNum2);
}
//전역함수 연산자 오버로딩
friend OverloadingOP operator+(const OverloadingOP& ref1, const OverloadingOP& ref2);
};
OverloadingOP operator+(const OverloadingOP& ref1, const OverloadingOP& ref2)
{
return OverloadingOP(ref1.m_iNum1 + ref2.m_iNum1, ref1.m_iNum2 + ref2.m_iNum2);
}
void main()
{
OverloadingOP op1(3, 4);
OverloadingOP op2(10, 10);
OverloadingOP op3 = op1 + op2;
op3.ShowMember();
//결과 : 13 / 14
}
- 전역함수로 연산자 오버로딩을 할 시, 해당 클래스의 멤버에 접근할수 있어야하므로 friend 선언을 해준다. (friend 키워드의 적절한 사용예)
연산자 오버로딩 주의점
- 연산자 오버로딩이 멤버함수, 전역함수로 둘 다 존재할 경우, 멤버함수로 오버로딩된 함수가 우선시되어 호출되므로, 특별한 경우가 아니라면 멤버함수 기반으로 연산자 오버로딩을 하는것이 좋다.
- 매개변수의 디폴트값 설정이 불가능하다.
- 연산자의 우선순위와 결합성은 바뀌지 않는다. (연산자가 지니는 우선순위와 결합성은 그대로 따라간다.)
단항연산자의 오버로딩
- 단항연산자(++, --)는 매개변수가 없다.
- 멤버함수 연산자 오버로딩 : class.operator++()
- 전역함수 연산자 오버로딩 : operator++(class)
- 단항연산자의 전위, 후위 구분은 int로 구분한다.
- 전위 : operator++()
- 후위 : operator++(int)
※ int는 데이터를 전달하는 뜻이 아닌, 단순히 전위와 후위를 구분하기 위해서 사용하는것이다.
- 단항연산자 오버로딩 예제
#include <iostream>
using namespace std;
class OverloadingOP
{
private:
int m_iNum1, m_iNum2;
public:
OverloadingOP(int n1 = 0, int n2 = 0) : m_iNum1(n1), m_iNum2(n2) { }
void ShowMember()
{
cout << m_iNum1 << " / " << m_iNum2 << endl;
}
//전위
OverloadingOP& operator++()
{
m_iNum1++;
m_iNum2++;
return *this;
}
//후위
const OverloadingOP operator++(int)
{
const OverloadingOP returnValue(m_iNum1, m_iNum2);
m_iNum1++;
m_iNum2++;
return returnValue;
}
};
void main()
{
OverloadingOP op(5, 10);
(++op).ShowMember();
(op++).ShowMember();
//결과
//6 / 11
//6 / 11
}
- C++가 ++(++obj)의 연산은 허용하되 (obj++)++를 허용하지 않는 연산특성을 가지고 있으므로 후위증감연산자의 경우 반환값을 const로 지정한다.
단항연산자의 오버로딩 시 교환법칙의 문제 해결하기
- 교환법칙 : A + B와 B + A의 결과가 서로 같음을 뜻한다. 즉, 연산자를 중심으로 한 피연산자의 위치는 연산 결과값이 같다는 법칙이다. (곱셈, 덧셈 연산이 있음)
- 자료형이 다른 두 피연산자를 대상으로 연산을 해야하는 경우, 형 변환으로 하여 자료형을 맞춘 다음에 연산이 이루어져야한다.
- 연산자 오버로딩을 이용하면 위와 같은 규칙에 예외를 둘 수 있다.
- 교환법칙 예외두기 예제
#include <iostream>
using namespace std;
class OverloadingOP
{
private:
int n;
public:
OverloadingOP(int x) : n(x){ }
void ShowMemver()
{
cout << n << endl;
}
//이 오버로딩은 OverloadingOP * int만 허용한다.
OverloadingOP operator*(int i)
{
return OverloadingOP(n * i);
}
//이 오버로딩은 int * OverloadingOP만 허용한다.
friend OverloadingOP operator*(int i, OverloadingOP& ref);
};
OverloadingOP operator*(int i, OverloadingOP& ref)
{
return OverloadingOP(ref.n * i);
//or
return ref * i;
}
void main()
{
OverloadingOP op1(5);
OverloadingOP op2 = op1 * 2;
OverloadingOP op3 = 2 * op1;
op2.ShowMemver();
op3.ShowMemver();
//결과
//10
//10
}
- 멤버함수의 형태로 오버로딩을 하게되면, 멤버함수가 정의된 클래스의 객체가 오버로딩 된 연산자의 왼편에 있어야 컴파일이 가능해진다.
- 우측에 클래스의 객체를 둔 연산이 필요할 때에는 전역함수의 형태로 오버로딩을 해야 컴파일이 가능해진다.
'Stack > C++' 카테고리의 다른 글
C++ 연산자 오버로딩 (대입, 인덱스 연산자) (0) | 2021.12.26 |
---|---|
C++ 네임스페이스(namespace), using (0) | 2021.12.12 |
C++ friend (0) | 2021.12.05 |
C++ 다중상속 (0) | 2021.11.22 |
C++ 멤버함수, 가상함수 동작원리 (0) | 2021.11.17 |