C++프로그래밍/C++ 객체지향

연산자 오버로딩

season97 2024. 9. 21. 14:23
728x90
반응형


※ 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를 붙혀주자 ★

 

728x90
반응형