본문 바로가기
C++/기초(두들낙서)

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

by Meaning_ 2022. 1. 14.
728x90
반응형

operator+

operator+는 예약어이다.

 

앞서 멤버 메서드 활용에서 동적함수 Add를 만들어줬는데 이걸 operator+로 만들어주면

https://we1cometomeanings.tistory.com/213

 

[C++ 기초] 멤버 메서드 활용

멤버 메서드의 선언, 정의 분리 멤버 메서드는 대부분 선언, 정의를 분리한다. 네임스페이스에서 배웠던 것 처럼 a,b,c 선언해주고 정의는 뒤에 빼준다. 근데 static 공부할 때 클래스를 네임스페이

we1cometomeanings.tistory.com

 

그러면 operator+의 기능은 무엇일까?

 

벡터 연산을 할 때 Vector c=a+b; 의 형태를 할 시 클래스끼리의 연산이 안돼서 에러가 떴다.

근데 operator+를 사용해주면 

 

 

a.operator+(b) 또는 심지어 a+b를 사용해줘도 된다.

 

그래서 출력값을 보면

 

 

두개 모두 출력값이 1,7로 같은 것을 확인할 수 있다.

 

a+b는 연산자 오버로딩을 한것으로 , +를 만나면 operator+ 메서드가 호출된다. 

 

+는 실질적으로 연산자이지만 자동으로 메서드도 호출한다.

 

연산자 오버로딩

operator+가 있으면 operator- 도 있고, 사칙연산도 가능할 것이다. 

벡터의 덧셈 -> 매개변수 벡터,반환값 벡터

벡터의 뺄셈 -> 매개변수 벡터,반환값 벡터

벡터의 실수배 -> 매개변수 실수,반환값 벡터

벡터와 실수의 나눗셈 -> 매개변수 실수,반환값 벡터

벡터의 내적 -> 매개변수 벡터, 반환값 실수 

 

총 5개의 연산을 할 수 있는 메서드를 만들어보았다.

 

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
#include <iostream>
 
using namespace std;
 
class Vector2 {
public:
    Vector2();
    Vector2(float x, float y);
 
    float GetX() const;
    float GetY() const;
 
 
 
    Vector2 operator+(const Vector2 rhs)const;
    Vector2 operator-(const Vector2 rhs)const;
    
    Vector2 operator*(const float rhs)const//벡터의 실수배
    Vector2 operator/(const float rhs)const;//벡터 나누기 실수 
    float operator*(const Vector2 rhs)const;//벡터내적
 
private:
    float x;
    float y;
};
 
Vector2 Sum(Vector2 a, Vector2 b) {
    
    return Vector2(a.GetX() + b.GetX(), a.GetY() + b.GetY());
}
 
 
int main() {
    Vector2 a(23);
    Vector2 b(-14);
    Vector2 c1 = a - b;
    Vector2 c2 = a * 1.6f;
    Vector2 c3 = a / 2;
    float c4 = a * b;
 
    cout << a.GetX() << " , " << a.GetY() << endl;
    cout << b.GetX() << " , " << b.GetY() << endl;
    cout << c1.GetX() << " , " << c1.GetY() << endl;
    cout << c2.GetX() << " , " << c2.GetY() << endl;
    cout << c3.GetX() << " , " << c3.GetY() << endl;
    cout << c4<<endl;
}
 
Vector2::Vector2() :x(0), y(0) {};
Vector2::Vector2(float x,float y):x(x), y(y) {}
float Vector2::GetX()const { return x; }
float Vector2::GetY()const { return y; }
Vector2 Vector2::operator+ (const Vector2 rhs)const
        return Vector2(x + rhs.x, y + rhs.y);
}
Vector2 Vector2::operator- (const Vector2 rhs)const {
    return Vector2(x - rhs.x, y -rhs.y);
}
Vector2 Vector2::operator* (const float rhs)const {
    return Vector2(x * rhs, y * rhs);
}
Vector2 Vector2::operator/ (const float rhs)const {
    return Vector2(x / rhs, y /rhs);
}
float  Vector2::operator*(const Vector2 rhs)const {
    return x * rhs.x + y * rhs.y;
}
cs

 

 

이러면 출력값이 잘 나오는걸 확인할 수 있다.

 

비멤버 연산자

 

그런데 의문이 하나 생긴다.

 

Vector2 c2=a*1.6f를 하며 c2객체를 만들어줬는데

반대로 (1.6f).operator*(a)를 해주면 에러가 뜬다. 이는 C언어에서 제공해주는 기본자료형의 연산자 오버로딩은 가능하지

않다. 1.6f는 기본자료형인 실수형이지 객체가 아니기에 에러가 뜬 것이다.

그래서 1.6f*a도 가능할 수 있게 해주기 위해 전역에 연산자 오버로딩이 가능하게 해볼것이다.

 

 

전역에 선언했기에 b.x나 b.y는 당연히 안되고 , 메서드의 상수화도 멤버메서드에서만 가능했기에 const도 뒤에 붙이지 못한다 

(const는 클래스 안에 있는 메서드에서만 뒤에 선언해서 메서드의 상수화를 시킬 수 있다. 전역에 선언된 애는 const 못붙인다)

 

이쯤에서 멤버 연산자와 비멤버 연산자의 차이점을 정리해보자.

 

멤버 연산자 비멤버 연산자
 멤버 메서드의 성질을 가지고 있으며, 자기 자신에 다른거(매개변수로 들어오는거) 연산해주는 것이기 때문에 우변에 필요한 값만 매개변수로 받음 
즉, 매개변수 1개
비멤버 연산자는 전역에 있기에 자기 자신이라는 개념이 없다.그래서 좌변과 우변을 동시에 매개변수로 받아줘야한다.
즉, 매개변수 2개

 

c3의 값을 1.6*a로 바꾸어서 출력해보면

 

c2와 c3가 같은 값으로 출력되는 것을 확인할 수 있다.

 

c2의 *연산자에 커서를 가져다 대니

얘는 멤버 연산자임을 알 수 있다. 

--> 매개변수 1개이고 Vector2(클래스를 네임스페이스 처럼 사용) ::operator* 이기에 Vector2 클래스 안에 있는 멤버 연산자이다.

 

c3의 *연산자에 커서를 가져다 대니

 

비멤버 연산자임을 알 수 있다.

--> 매개변수 2개, Vector2::operator* 같이 클래스를 네임스페이스로 사용한 기록이 없음. 

 

프렌드로 operator* 구현하기

수평적인 관계의 클래스 간에 멤버변수를 공유해야 할 경우에 프렌드를 쓴다.

하나의 클래스에서 다른 클래스의 내부 데이터에 접근해야할 경우 프렌드를 써서 권한을 준다.

프렌드를 통해 private멤버에 접근할 수있다!! (외부에서 private멤버에 접근)

 

한마디로 프렌드는 private로 숨겨놓은 캡슐화를 깨는 문법이라고 생각하면 된다.

 

  private에 접근할 수 있는 프렌드 함수를 통해서 operator* 을 구현해 볼 것이다.

 

Vector2의 private 필드에 있는 변수인 x와 y에 접근가능하다.

friend함수는 멤버변수에 선언해줬지만 일반함수처럼 쓸 수 있기에 Vector2 Vector2::operator* 이런식으로 어디 클래스 소속인지를 밝혀줄 필요가 없다!

그리고 메인함수에서 접근할 때도 

Vector2 vector;

Vector2 a(2,3);

vector.operator*(); <-- 이런식으로 할 필요도 없다. 왜냐면 operator*함수가 클래스

Vector2의 멤버함수가 아니기 때문이다. 그래서 그냥 operator*라고 하거나 어차피 연산자 오버로딩

되었기에 3*a 이런식으로 써줘도 된다. 

728x90
반응형

'C++ > 기초(두들낙서)' 카테고리의 다른 글

[C++기초] 동적할당  (0) 2022.01.15
[C++기초] 클래스 연습문제  (0) 2022.01.15
[C++ 기초] 멤버 메서드 활용  (0) 2022.01.14
[C++기초] 상수형 매개변수와 상수형 메서드  (0) 2022.01.14
[C++기초] static  (0) 2022.01.14

댓글