[C++] 연산자 오버로딩
연산자 오버로딩
- 연산자를 중복정의. 사용자 정의 자료형(클래스,구조체)에서 연산자를 재정의하는 것.
- 기본 연산자의 기능을 클래스(객체)에도 적용이 가능하다는 의미.
- 대부분의 연산자는 전역함수,클래스(구조체)에서 정의 가능하다.
연산자 오버로딩이 불가능한 연산자
. | 멤버 접근 연산자 |
.* | 멤버 포인터 연산자 |
:: | 범위 지정 연산자 |
? : | 삼항 연산자 |
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(10, 20);
Point b(40, 30);
Point c(5,5),d;
c = a + b;
c = 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 |