게임프로그래밍/C++

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

marmelo12 2022. 1. 15. 21:22
반응형

연산자 오버로딩

 - 연산자를 중복정의. 사용자 정의 자료형(클래스,구조체)에서 연산자를 재정의하는 것.

  - 기본 연산자의 기능을 클래스(객체)에도 적용이 가능하다는 의미.

 - 대부분의 연산자는 전역함수,클래스(구조체)에서 정의 가능하다.

 

연산자 오버로딩이 불가능한 연산자

. 멤버 접근 연산자
.* 멤버 포인터 연산자
:: 범위 지정 연산자
? : 삼항 연산자
sizeof 바이트 크기 계산 연산자
typeid RTTI 관련 연산자
static_cast 형변환 연산자
dynamic_cast 형변환 연산자
const_cast 형변환 연산자
reinterpret_cast 형변환 연산자

 

형식

리턴타입 operator연산자키워드 (매개변수..)

 

멤버 연산자 오버로딩 : 클래스 및 구조체 내부에 존재하는 연산자 오버로딩.

 - 왼쪽 피연산자가 자기자신, 오른쪽 피연산자가 매개변수

전역 연산자 오버로딩 : 전역공간에 존재하는 연산자 오버로딩.

 - 왼쪽 피연산자가 첫번째 매개변수, 오른쪽 피연산자가 두번째 매개변수

 -> this가 없기 떄문

 

간단한 사용 예제. (멤버 연산자 오버로딩)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Point
{
public:
    Point() : m_x(0), m_y(0) { }
    ~Point() { }
    Point(int x, int y) : m_x(x), m_y(y) { }
 
public:
    void Print() { std::cout << m_x << " " << m_y << std::endl; }
private:
    int m_x, m_y;
 
};
cs

위와 같이 Point(점)을 나타내는 클래스가 있다.

기본적으로 사용자 정의 자료형은 연산자 오버로딩을 사용하지 않는 이상 연산자 이용이 불가능하다.

C++에서는 이를 해결하기 위해서 제공하는게 연산자 오버로딩.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Point
{
public:
    Point() : m_x(0), m_y(0) { }
    ~Point() { }
    Point(int x, int y) : m_x(x), m_y(y) { }
 
    // 멤버 연산자 오버로딩
public:
    Point operator+(const Point& other) // 덧셈(이항) 연산자
    {
        Point temp(*this);
        temp.m_x += other.m_x;
        temp.m_y += other.m_y;
        return temp;
    }
   Point& operator++() // 전위 증가 연산자 (단항)
    {
        this->m_x += 1;
        this->m_y += 1;
return *this;
    }
    Point operator--(int// 후위 감소 연산자 (단항)
    {
        Point temp(*this);
        this->m_x -= 1;
        this->m_y -= 1;
        return temp;
    }
public:
    void Print() { std::cout << m_x << " " << m_y << std::endl; }
private:
    int m_x, m_y;
 
};
  cs

결과.

이항 연산자는 피연산자가 두 개여야 하므로 자기자신(왼쪽 피연산자 기준이 된다)을 제외한 오른쪽 피연산자를 받기위해 매개변수를 선언해야 한다.

단항 연산자는 불필요. 다만 후위 증감 연산자는 구분을 위해 해당 자료형을 넣어준다.

1
2
3
4
5
6
Point a(1020);
Point b(4030);
Point c(5,5),d;
 
= a + b; 
= a.operator+(b); // 위와 동일하다
cs

연산자의 종류는 많고(인덱스 연산자등) 필요할때마다 구분(단항,이항등)하여 사용하면 된다.

 

전역 연산자 오버로딩

연산자 오버로딩을 할 때 멤버함수로 연산자 오버로딩하는것 외에도 전역 함수로도 연산자 오버로딩이 가능하다.

하지만 사용되는 문법 키워드가 하나 더 존재하는데 바로 friend.

friend 키워드는 클래스 내부에 friend로 선언된 함수,클래스는 자신의 private(protected)영역에 접근이 가능하다.

1
2
3
4
5
class Point
{
    // 전역함수로 연산자를 오버로딩하니 이항 연산자는 두개의 매개변수를 받아야 한다.
    // friend키워드.
    friend Point operator*(const Point& lhs, const Point& rhs);
cs

 

 

하지만 위와 같이 굳이 멤버 함수로 연산자 오버로딩을 해도되는데 저렇게 하지는 않는다.

전역 연산자 오버로딩을 사용하는 흔한 예제는 바로 객체를 대상으로 바로 cout(출력)하는 것.

 

<< >> 입출력 연산자 오버로딩은 멤버함수로는 구현할 수 없고 전역함수로만 구현할 수 있다.

 - cout,cin 각각 C++표준의 istream,ostream 클래스안에 존재하는 객체.

 - 그렇기에 우리가 그 내부에 멤버 연산자 오버로딩을 구현할 수 없다.

  -> C++표준은 사용자가 수정할 수 없음.

 

따라서 입출력 연산자 오버로딩은 전역 연산자 오버로딩으로 구현해야 한다.

1
2
3
4
5
6
7
8
9
10
11
class Point
{
    // 전역함수로 연산자를 오버로딩하니 이항 연산자는 두개의 매개변수를 받아야 한다.
    // friend키워드.
    friend Point operator*(const Point& lhs, const Point& rhs);
    // ostream 객체를 반환 해야한다.(참조) 이어서 cout << a << b << c 출력이 가능하도록.
    friend std::ostream& operator << (std::ostream& os, const Point& rhs)
    {
        os << rhs.m_x << " " << rhs.m_y << " ";
        return os;
    }
cs

 

반응형