연산자 오버로딩
※ C / C++을 이미 알고 있으나 개인적인 복습 및 공부를 위해 포스팅 하는 글이므로
C++에 대한 구체적인 정보를 담고 있지 않습니다.
▶ 연산자 오버로딩
ㆍ 말 그대로 연산자를 오버로딩해서 + - 등등 다른기능을 수행하게 해주는 것
ㆍ 함수도 맴버함수 vs 전역함수가 존재하는 것 처럼, 연산자 함수도 두가지 방식으로 만들 수 있다.
※ 언제 쓰는가?
ㆍ 아래 pos끼리 덧셈뺼셈을 지원하게 하고싶다...
1) 맴버 연산자 함수 version
class Position
{
public:
int _x;
int _y;
};
int main()
{
Position pos;
pos._x = 0;
pos._y = 0;
Position pos2;
pos._x = 1;
pos._y = 1;
//Position pos3 = pos + pos2; //해당 코드는 오류... 우리는 이걸 정의해 준적이 없다.
return 0;
}
class Position
{
public:
// 함수의 선언 예시
RET FUNC_NAME(ARG_LIST)
{
}
// 연산자 오버로드도 비슷하다
Position operator+(const Position& arg)
{
Position pos;
pos._x = _x + arg._x;
pos._y = _y + arg._y;
return pos;
}
public:
int _x;
int _y;
};
int main()
{
Position pos;
pos._x = 0;
pos._y = 0;
Position pos2;
pos._x = 1;
pos._y = 1;
Position pos3 = pos + pos2;
pos3.operator+(pos2);
return 0;
}
ㆍ 이제 정상적으로 작동한다. pos3에 대한 두 코드는 동일한 의미를 지닌다.
ㆍ 편의상 생략해서 + 연산자를 사용할 수 있게 해주는것
ㆍ a oper b 형태에서 왼쪽 기준으로 실행됨 (a가 클래스여야 가능, a를 "기준 피연산자" 라고 한다_
한계) a가 클래스가 아니면 사용 못함 -> 무슨소리냐?
int main()
{
Position pos;
pos._x = 0;
pos._y = 0;
Position pos2;
pos2._x = 1;
pos2._y = 1;
Position pos3 = pos + pos2;
pos3.operator+(pos2);
Position pos4 = 1 + pos3; //해당 부분오류
return 0;
}
ㆍ 맨 아래줄 pos4는 오류다. 기준피연산자가 클래스가 아니기 때문이다......
※ 해결법
2) 전역 연산자 함수 version
ㆍ a oper b 형태라면 a,b 모두를 연산자 함수의 피연산자로 만들어 준다.
Position operator+(int a, const Position& b)
{
Position ret;
ret._x = b._x + a;
ret._y = b._y + a;
return ret;
}
ㆍ 전역으로 선언하면 오류가 해결되긴 한다.
▶ 근데 둘중 하나만 지원하는 경우도 있기때문에 둘 다 알아야하고, 누가 더 좋고 그런건 없다.
ㆍ 대표적으로 대입 연산자는 전역으로 선언 못한다
class Position
{
public:
void operator=(int arg)
{
_x = arg;
_y = arg;
}
public:
int _x;
int _y;
};
int main()
{
Position pos5;
pos5 = 5;
return 0;
}
ㆍ 맴버에 선언하면 잘 된다.
void operator=(const Position& a, int b)
{
a._x = b;
a._y = b;
}
ㆍ 하지만 전역에서 사용하면 오류가 발생한다!
ㆍ 대입이라는걸 잘 생각해보자... 왼쪽에있는곳에 오른쪽놈을 넣어주겠단 소리인데 대입에서 이걸 반대로 수행하면 위험 할 수 있으니 막아뒀다 라고 이해하자
※ +말고 다른 연산자도 다 오버로딩이 가능하다!
bool operator==(const Position& arg)
{
return _x == arg._x && _y == arg._y;
}
위 = 대입연산자를 void형으로 하니 좀 아쉬운게 있다
int a = 1;
int b = 2;
int c = 3 + (a + b);
ㆍ 대입이라 함은 c처럼 저런거도 가능해야한다.. 하지만 void형을 반환하기 때문에 지금 저렇게 사용할 수가 없다
class Position
{
public:
Position& operator=(int arg)
{
_x = arg;
_y = arg;
return *this;
}
public:
int_x;
int_y;
};
ㆍ 이렇게 자기 자신의 참조를 반환하면 된다... this*을 이용해 내 자신의 참조를 반환해줬다.
Position pos5;
pos5 = 5;
pos5 = (pos5 = 5);
ㆍ 이제 대입의 기능이 잘 작동한다.
▶ 복사 대입 연산자 / (=대입 연산자중, 자기 자신의 참조타입을 매개변수 로 받는 것)
Position& operator=(Position& arg)
{
_x = arg._x;
_y = arg._y;
return *this; //내 자신의 참조를 가져오고싶다
}
ㆍ 말이 복잡해서 그렇지 그냥 말 그대로다. 대입은 대입인데 복사 형태로 이뤄짐
[복사 생성자] [복사 대입 연산자] 등 복사가 좀 강조되는 이유는 추후 동적할당 포스팅에서 다루겠다.
# 모든 연산자를 다 오버로딩 할 수 있는것은 아니다.( :: . .* 이런건 오버로딩 불가)
# 모든 연산자가 다 2개 항이 있는건 아님 (++ , -- 가 대표정 (항이1개인 단항연산자))
# 증감연산자 ++ --를 구현하려면 어떻게 해야될까? (앞과 뒤 다 붙힐수있잖아 ++a, a++)
1. 전위형은 그냥 operatotr++() 하면된다.
Position& operator++() //전위
{
_x++;
_y++;
return *this;
}
pos1 = ++(++pos2) //가능
ㆍ 그냥 자기자신 참조를 뱉어주면 된다
2. 후위형은 operator++(int)를 해줘야한다
int a = (b++)++; //이건안됨
Position operator++(int) //int 이름을 지어줄 필요도 없음 후위
{
Position ret = *this;
_x++;
_y++;
return ret;
}
ㆍ 근데 문제가 생긴다
ㆍ pos5 = pos3++; // 이거안된다.. 왜 안될까? 이유는 코드를 보면 만들어둔 ++연산자는 반환형이 복사값을 준다
마치 이런상황이다 : pos5 : "pos& 내놔!!!" pos3 : " ㄴㄴㅋㅋ pos복사값 줄게" 이러고있는 상황이다.
해결법 : const pos&줘~ 라고 요구하면된다.
Position& operator=(const Position& arg)
{
_x = arg._x;
_y = arg._y;
return *this; //내 자신의 참조를 가져오고싶다
}
★ ★ ★자기 자신 참조형 매개변수에는 const를 붙혀주자 ★ ★ ★