연산자 오버로딩
Vector result = vector1 + vector2;
Vector result = vector1.operator+(vector2);
반환형 함수이름 인자
Vector operator+(const Vector& rhs) const;
형식 손에 익을 정도로 술술 쓸 줄 알아야
마지막에 const는 자신의 값은 변하지 않으므로
* 멤버 연산자 작성하는 법
<return-type><class-name>::operator<operator-symbol>(<argument-list>)
{
}
Vector Vector::operator-(const Vector& rhs) const;
Vector Vector::operator*(const Vector& rhs) const;
Vector Vector::operator/(const Vector& rhs) const;
* friend 키워드
클래스 정의 안에 friend 키워드를 사용 가능
> 다른 클래스나 함수가 나의 private 또는 protected 멤버에 접근할 수 있게 허용
(friend는 내 금고에 있는 거 다 털어가도 돼~)
* 연산자 오버로딩과 const
멤버 변수의 값이 바뀌는 것을 방지
불필요한 개체의 사본이 생기는 것을 방지
최대한 많은 곳에 const 붙일 것!
* 제한사항
1. 오버로딩된 연산자는 최소한 하나의 사용자 정의 형을 가져야 함
Vector operator+(const Vector& rhs) const;
안 그러면 이미 존재하는 연산자일 수도
2. 오버로딩된 연산자는 피연산자 수를 동일하게 유지해야 함
Vector vector1;
+vector1; // 불가능. +연산자는 2개의 피연산자를 가짐
그러나 단항 +연산자를 오버로딩 할 순 있음
3. 새로운 연산자 부호를 만들 수 없음
Vector operator@(const Vector& rhs) const; // 불가능
4. 오버로딩 할 수 없는 연산자가 존재
. .* :: ?:
* 연산자 오버로딩을 남용하지 말자
Vector vector = vector1 << vector2; // ? 뭐 하고 싶은거야
차라리 함수를 이쁘게 만들자
* 대입(assignment)연산자 operator=
복사 생성자와 거의 동일.
차이 1. 따끈따끈하게 갓 만들어진 개체냐(복사 생성자) 이미 있는 개체냐(대입 연산자)
2. 대입 연산자는 메모리를 해제해 줄 필요가 있을 수도...
복사 생성자를 구현했다면 대입 연산자도 구현해야 할 것임
* 암시적 operator=
operator= 구현이 안 되어 있으면 컴파일러가 operator= 연산자를 자동으로 만들어 줌 (얕은 복사)
* 암시적 함수들(매개변수 없는 생성자, 복사 생성자, 소멸자, 대입(=) 연산자) 을 "지우는" 법 (고대 C++ 버전)
Vector() {}
Vector(const Vector& other) {}
~Vector() {}
Vector& operator=(const Vector& rhs);
private 멤버로 넣어버리자
* Vector.h
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
35
36
37
38
|
#pragma once
#include <iostream>
class Vector
{
public:
Vector();
Vector(int x, int y);
~Vector();
Vector operator+(const Vector& rhs) const;
// friend : 다른 클래스나 함수가 나의 private 또는 protected 멤버에 접근할 수 있게 허용
// friend <return-type> operator<operator-symbol>(<argument-list>);
// firend 함수는 멤버 함수가 아님!!!
friend std::ostream& operator<<(std::ostream& os, const Vector& rhs);
// 좌항의 값이 변하길 기대하므로 마지막에 const 사용 X
// 개체 복사를 막기위해 Vector&
Vector& operator+=(const Vector& rhs);
bool operator==(const Vector& rhs) const;
Vector operator*(const Vector& rhs) const;
Vector operator*(int multiplier) const;
friend Vector operator*(int multiplier, const Vector& v); // 좌항이 int일 경우도 똑같이 동작하도록
//전역 함수 만들고 매개변수 2개
Vector& operator*=(const Vector& rhs);
Vector& operator*=(int multiplier);
private:
int mX;
int mY;
};
|
cs |
* Vector.cpp
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#include "Vector.h"
Vector::Vector()
: mX(0), mY(0)
{
}
Vector::Vector(int x, int y)
: mX(x), mY(y)
{
}
Vector::~Vector()
{
}
Vector Vector::operator+(const Vector& rhs) const
{
Vector sum;
sum.mX = mX + rhs.mX;
sum.mY = mY + rhs.mY;
return sum;
}
// <return-type> operator<operator-symbol>(<argument-list>)
// 전역 함수는 어디에 써도 상관은 없지만, 같이 쓰이는 클래스의 cpp에 넣어 놓는게 일반적
// 반환값이 void면 Chaining 불가능
// os에 뭔가 쓰니까 const 붙이지 않았음. 반환형도 마찬가지(내가 쓰던거 반환해 줄테니까 너도 마음대로 써~)
std::ostream& operator<<(std::ostream& os, const Vector& rhs)
{
//Vector 클래스에서 friend 선언을 했으므로 private 멤버 변수 접근 가능
os << rhs.mX << ", " << rhs.mY;
return os;
}
Vector& Vector::operator+=(const Vector& rhs)
{
mX += rhs.mX;
mY += rhs.mY;
return *this; // this : 나 자신을 가리키는 포인터
// *this : 나(개체), 반환하면 참조로 받아준다.
}
bool Vector::operator==(const Vector& rhs) const
{
return (mX == rhs.mX && mY == rhs.mY);
}
Vector Vector::operator*(const Vector& rhs) const
{
Vector result(mX * rhs.mX, mY * rhs.mY);
return result;
}
Vector Vector::operator*(int multiplier) const
{
Vector result(mX * multiplier, mY * multiplier);
return result;
}
Vector operator*(int multiplier, const Vector& v)
{
Vector result(v.mX * multiplier, v.mY * multiplier);
return result;
}
Vector& Vector::operator*=(const Vector& rhs)
{
mX *= rhs.mX;
mY *= rhs.mY;
return *this;
}
Vector& Vector::operator*=(int multiplier)
{
mX *= multiplier;
mY *= multiplier;
return *this;
}
|
cs |
* main.cpp
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include <iostream>
#include "Vector.h"
int main()
{
Vector v1(10, 20);
Vector v2(3, 17);
Vector sum = v1 + v2; // + 연산자 오버로딩
sum = v1.operator+(v2); // 완전히 같은 의미
//하고 싶은 짓
//std::cout << v1; // 10, 20 콘솔창에 뜨기 바람
//private 멤버 변수 접근 불가
//std::cout << v1.mX << ", " << v1.mY << std::endl;
//첫 번째 시도 : Getter 만들기
//모든 멤버 변수에 Getter 만드는 것도 좀...
//std::cout << v1.GetX() << ", " << v1.GetY() << std::endl;
//두 번째 시도 : << 연산자 오버로딩
//std::cout.operator<<(v1); // cout이 어디에 들어있지?
// ostream 클래스에 넣으면 되지 않나?
// 남이 만든 파일에 손대는것 자체가 말이 안돼...
// 좌항에 해당되는 개체에 접근 권한이 없을 때,
// 전역 함수를 만들어야 함
std::cout << v1 << std::endl; // << 반환형이 void 였다면 불가능
v1 += v2;
std::cout << v1 << std::endl;
std::cout << (v1 == v2) << std::endl;
std::cout << (v1 * v2) << std::endl;
std::cout << (v1 * 3) << std::endl;
std::cout << (3 * v1) << std::endl;
v1 *= v2;
std::cout << v1 << std::endl;
v1 *= 3;
std::cout << v1 << std::endl;
return 0;
}
|
cs |
출처 : 포큐아카데미 C++ 언매니지드 프로그래밍