일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- vector capacity
- increment operator
- std::cout
- delete function
- std::endl
- operator overloading
- base from member
- new&delete
- pointer to member data
- C++
- virtual function table
- 더 지니어스 양면포커
- discord bot
- dynamic_cast
- std::ostream
- c++ basic practice
- c++ multi chatting room
- constructor
- suffix return type
- virtual inheritance
- placement new
- std::vector
- diamond inheritance
- return by reference
- member function pointer
- vector size
- virtual destructor
- virtual function
- this call
- conversion constructor
- Today
- Total
I'm FanJae.
[C++] Operator Overloading I 본문
※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.
1. 연산자 재정의(Operator Overloading)
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
};
int main()
{
Point p1{1, 1};
Point p2{2, 2};
int n1 = 10 + 20; // ok
Poiint p3 = p1 + p2; // ?
}
- 연산자 재정의(Operator Overloading) 이라는 것은 사용자 정의 타입의 객체에 대해서도 +, - 등의 연산자를 사용할 수 있게 하는 문법이다.
Point p3 = p1 + p2;
- 즉, 위와 같은 사용자 정의 타입 객체도 연산자 재정의를 통해 연산을 할 수 있다.
① a + b를 컴파일러가 해석 하는 방법
- a, b가 모두 primitive type(int, double 등)인 경우에는 미리 정해진 방식으로 덧셈을 수행한다.
- a, b 중 한 개라도 사용자 정의타입이 있는 경우 operator+ 라는 이름의 약속된 함수를 호출한다.
- operator+ 함수를 찾을 수 없는 경우 -> + 연산을 할 수 없다는 에러가 발생한다.
② p1 + p2 코드를 컴파일러가 해석하는 방법
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
};
int main()
{
Point p1{1, 1};
Point p2{2, 2};
Poiint p3 = p1 + p2; // ?
}
- operator+를 만드는 방법은 크게 2가지가 존재한다.
- 이는 멤버가 아닌 함수로 구현하는가와 멤버 함수로 구현하느냐에 따라 달라진다.
③ operator+를 구현하는 방법
멤버가 아닌 함수로 구현 | - operator+ (p1, p2) - 함수 인자는 2개 |
멤버 함수로 구현 | - p1.operator+(p2) - 함수 인자는 1개 |
(1) 방법 1. 멤버가 아닌 함수로 구현
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
};
Point operator+(const Point& p1, const Point& p2)
{
Point pt{p1.x + p2.x, p1.y + p2.y};
return pt;
}
int main()
{
Point p1{1, 1};
Point p2{2, 2};
Poiint p3 = p1 + p2; // ?
}
- 이와 같이 구현할 수 있다.
- 이 방법의 경우는 멤버에 직접 접근해야하기 때문에, 멤버 데이터 x, y에 접근하기 위해서 다음과 같은 작업도 진행해야 한다.
① x, y 를 public 영역에 선언한다.
② get_x(), get_y() 멤버 함수를 제공한다.
③ operator+ 를 friend 함수로 등록한다.
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
friend Point operator+(const Point& p1, const Point& p2);
};
(2) 방법 2. 멤버 함수로 구현
- 멤버 함수로 구현할 경우, 아래와 같은 사항에 유의해야 한다.
① + 연산자는 이항 연산자 이지만 operator+ 멤버 함수의 인자는 한 개이다.
② 상수 객체도 덧셈을 할 수 있어야 하므로 const member function으로 구현한다.
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
Point operator+(const Point& p) const
{
Point pt{p.x + x, p.y + y};
return pt;
}
};
int main()
{
Point p1{1, 1};
Point p2{2, 2};
Poiint p3 = p1 + p2; // p1.operator+(p2)
}
※ 그렇다면 2개 동시에 제공하면 어떻게 될까?
1-1. 멤버 함수와 멤버 함수가 아닌 함수를 모두 제공하는 경우
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
Point operator+(const Point& p) const
{
Point pt{p.x + x, p.y + y};
return pt;
}
friend Point operator+(const Point& p1, const Point& p2)
};
Point operator+(const Point& p1, const Point& p2)
{
Point pt{p1.x + p2.x, p1.y + p2.y};
return pt;
}
int main()
{
Point p1{1, 1};
Point p2{2, 2};
Poiint p3 = p1 + p2; // p1.operator+(p2)
}
- 이 경우, 컴파일 에러가 발생한다.
- 반드시 둘 중 한개만 제공해야 한다.
① 멤버 함수 vs 멤버가 아닌 함수
- private 멤버에 접근하기에는 멤버 함수가 좋다.
- 하지만 1번째 인자가 사용자 정의 타입이 아닌 경우, 멤버 함수로 만들 수 없는 경우가 있다.
int main()
{
int n1 = 10;
Point p1{1, 1};
Point p2{2, 2};
Point ret1 = p1 + p2; // p1.operator+(Point)
Point ret2 = p1 + p2; // p1.operator+(int) // 이걸 만들면 가능하다.
Point ret3 = n1 + p2; // n1.operator+(Point) // Error
}
- 위와 같이 n1이 먼저 나오면, 멤버 함수를 만들 수 없기 때문에 불가능하다.
- 정리하면 아래와 같다고 할 수 있다.
멤버 함수 | 멤버가 아닌 함수 | |
p1+p2 | p1.operator+(point) | operator+(Point, Point) |
p1+n1 | p1.operator+(int) | operator+(Point, int) |
n1+p1 | 만들 수 없다 | operator+(int, Point) |
2. 연산자 재정의 주의 사항
2-1. 핵심 정리
(1) 2가지 형태로 만들 수 있다.
- 멤버 함수 (인자 개수가 1개)
- 멤버가 아닌 함수 (인자 개수 2개)
① operator+ 함수 이름을 직접 사용해서 호출 할 수 있다.
멤버가 아닌 함수로 구현 | operator+(p1, p2); 위 코드로 직접 호출이 가능 |
|
멤버 함수로 구현 | p1.operator+(p2); 위 코드로 직접 호출 가능 |
#include <string>
int main()
{
std::string s1 = "hello";
std::string s2 = "world";
auto ret1 = s1 + s2;
// auto ret2 = s1.operator+(s2); // error
auto ret3 = operator+(s1,s2);
}
- operator+(s1,s2); 일때 호출 되는 것으로 볼때, string은 멤버 함수가 아닌 일반 함수로 만들었음을 확인할 수 있다.
② 연산자 재정의와 const member function
- 객체의 상태가 변경되지 않은 연산자는 const member function으로 해야한다.
class Point
{
int x{0};
int y{0};
public:
Point() = default;
Point(int x, int y) : x{x}, y{y} {}
// p1 이 상수 객체라도 "p1 + p2" 할수 있어야 한다. 상수 멤버 함수로 작성
Point operator+(const Point& p) const
{
Point pt{p.x + x, p.y + y};
return pt;
}
// p1 이 상수 객체라면 "p1 += p2" 는 할 수 없다. "비 상수" 멤버 함수로 작성.
Point& operator+=(const Point& p)
{
x += p.x;
y += p.y;
return *this;
}
};
int main()
{
const Point p1{1, 1};
Point p2{2, 2};
auto ret = p1 + p2; // ok
// p1.operator+(p2)
p1 += p2; // p1이 수정되어야 함.
// 원래 대로라면 error. 나와야함.
// p1.operator+=(p2) 가 애초에 호출 되어선 안됨.
}
- p1 += p2;의 경우는 p1의 값이 수정된다. 따라서 이는 객체의 상태가 변화한다는 의미이다.
- 즉, const member function으로 해야한다.
+ | operator+(const Point& p2) const operator+(const Point& p1, const Point& p2) |
+= | operator+(const Point& p2) operator+(Point &p1, const Point& p2) |
※ +일때와 +=가 어떤 차이가 있는지 예시로, 비상수/상수 멤버 함수로 만드는지 잘 구분해야한다.
③ 인자가 모두 primitive type인 경우는 overloading을 할 수 없다.
int operator+(int a, int b) // error
{
return a-b;
}
int ret = 3 + 2; // ?
- operator+() 함수의 인자 중 한 개 이상은 반드시 사용자 정의 타입이어야 한다.
④ 인자의 개수를 변경할 수 없다.
void operator+(Point p1, Point p2, Point p2) // error
{
// +는 이항 연산자 이므로
// member : 1개의 인자
// non-member : 2개의 인자
}
- +는 기본적으로 이항 연산자이다. 따라서, 이항 연산자이므로, 추가 인자를 받는것은 불가능하다.
⑤ 디폴트 파라미터(Default Parameter)를 사용할 수 없다.
void operator+(Point p1, int n = 0) // error
{
}
⑥ 새로운 연산자를 만들 수 없다.
void operator+*(Point p1, Point p2) // error
{
}
- 기존 C++에 없는 연산자를 만드는 행위는 불가능하다.
⑦ [], (), ->, = 연산자는 멤버함수로만 만들 수 있다.
void operator[](int idx) // error
{
// 멤버 함수가 아니면 error
}
⑧ 아래 연산자는 재 정의 할 수 없다.
. .* :: : ?:
sizeof typeid
static_cast dynamic_cast reinterpret_cast const_cast
⑨ 중요한 연산자
++ | STL 의 반복자 등을 만들 때 사용 |
[] | v[0] = 10; 의 표기법 지원 |
() | 함수 객체(function object) |
->, * | 스마트 포인터(smart pointer) |
= | 객체의 복사 |
⑩ 연산자 우선 순위는 변경할 수 없다
⑪ + 와 = 를 모두 재정의 해도, += 이 자동 지원되는 것이 아니다.
※ 주의 사항이 상당히 많지만, 대부분의 것은 충분히 어렵지 않게 이해할 수 있는 내용ㅇ다.
'C++ > Basic' 카테고리의 다른 글
[C++] Operator Overloading III (0) | 2024.08.25 |
---|---|
[C++] Operator Overloading II (0) | 2024.08.24 |
[C++] Multiple Inheritance, Diamond Inheritance, Virtual Inheritance (0) | 2024.08.23 |
[C++] RTTI, Dynamic Cast (0) | 2024.08.22 |
[C++] Virtual Function Table (0) | 2024.08.22 |