강의/computer science

[computer science] c++의 operator overloading/연산자 구현하기 1편

하기싫지만어떡해해야지 2024. 10. 14. 16:19

이 게시글은

서울대학교 데이터사이언스대학원

조요한 교수님의

데이터사이언스 응용을 위한 컴퓨팅 강의를

학습을 위해 재구성하였습니다.


 

저번 시간에는 c++의 class 내부에서

method를 구현하는 법을 배웠다면

이번시간에는 class의 바깥에서

method 구현하는 법을 정리해보려고한다

 

그리고 그와 함께

operator overloading까지

같이 정리해보려구한다

 

그럼 시작..!

 

 

Out-of-Class Definition

 

 

위 ppt의 코드를 잘 읽어보자

SimpleVector라는 class 내부에

 

void addElement(T element);

int getSize() const;

와 같이 함수들이 정의되어있는데

자세한 구현은 없이

prototype만 정의되어 있는 것을 

확인할 수 있다

 

실제 메소드들이 어떻게 작동하는지는

class 바깥으로 빼서 정의가 가능하다

 

 

 

class의 바깥에서 정의해주기 위해선

반드시 SimpleVector::와 같은

scope resolution operator를

작성해줘야한다

 

위는 앞에서는 prototype만 있었던

SimpleVector의 method들을

class 바깥에서 구현한 부분이다

 

그렇다면 이렇게

class 바깥에 method를

구현하는 것의

장점은 무엇일까?

 

 

우선 interface가 simple해진다

 

그리고

class definition은 header로

구현부는 source file로 구분할 수 있다

이게 왜 장점인가하면

프로그래머가 class를 구현하고

구체적인 implementation을 수정해야할 때

source file만 찾아가서 수정한 뒤

배포하면 되기 때문이다

 

implementation이 한 개의 파일에 있다면

결국 그 파일을 가져다쓰는

모든 파일들을 전부다 새로 compile해줘야햐는데

위와같은 방식으로 하면

source file만 다시 compile을 해주면 된다

 

하지만 class template를 쓰는 경우는

메소드의 정의와 implementation이

반드시 같이 있어야한다

그래야 compiler가 동시에 확인을

할 수 있기 때문이다

 

 

Class Pointers

 

 

class를 pointer로 만들어서

사용하는 방법도 간단하게 알아보자

 

ppt에는 총 4가지의 방법이

나와있다

 

제일 처음을 보면

포인터 변수를 선언과 함께

null포인터로 초기화해줬다

 

기존의 local 변수로 초기화해주거나

선언과 동시에 새로운 object를

dynamic하게 할당해줄 수도 있다

 

 

다른 Pointer 변수들과 역시 동일하게

할당을 해줬으면 반드시

delete를 통해서 할당을 해제해줘야한다

 

아니면

smart pointer를 사용할 수 있다

 

 

pointer변수로 정의된

class에는 어떻게 접근할 수 있을까

 

화살표(->)로 접근하던가

*intVecPtr처럼 작성한 뒤

dot operator(.)로 접근할 수 있다

 

 

Operator Overloading

 

그렇다면 이제

operator overloading에 대해 배워보자

 

우리가 흔히 쓰는

i++

i--

str1 + str2

cout << intVal

같은 코드에서

++, --, +, << 등을

연산자(operator)라고 부른다

 

이런 연산자는 일종의

symbol인데

우리가 흔히 알고있는 규칙대로

위 연산자를 쓸 수 있는 이유는

이미 코드 상에 정의가 되어있기 때문이다

또한 프로그래머가 원하는 방식으로

operator가 어떻게 연산되는지

다시 정의를 해줄 수도 있다

 

이를 operator overloading이라고 한다

 

우리가 흔히 아는

operator convention이 있다

 

++는 1 증가

--는 1 감소

+는 두 요소를 합해주기 등

 

일반적으로 흔히 정의되어있는

convention을 따라가게

정의를 해주면 된다

convention을 따라가게 정의해야

user의 expectation을 맞출 수 있다

 

프로그래머가 원하는 방식으로

정의를 해도 상관은 없지만

unconventional하게 할 경우

헷갈리는 문제가 발생할 수 있으므로

보통 convention을 따르도록 프로그래밍한다

 

그럼 이제 차근차근

각 연산자마다

어떻게 실제로 구현을했는지

알아보도록하자

 

 

Subscript Operator

 

우리가 보통 vector의 index요소에 접근할 때

intVec[1]

이러한 방식으로 많이 접근한다

이 때 뒤의 []이 subscript operator이다

 

구현방법은 위 코드를 참고해보자

우선 외부에서 SimpleVector라는

클래스 내부의 Method를 구현하는 것이므로

반드시 SimpleVector::를 달아준다

 

그다음 operator[]를 해주면

subscript operator의 구현을

해주겠다는 의미이다

input으로는 int index를 받는다

반환값으로는 T타입을 받아야하니깐

T의 reference값을 준다

 

그다음 return값으로는

SimpleVector class의

기존에 정의되어있던 array에서

array[index]를 반환해준다

 

그럼 밑의 main함수와 같이

SimpleVector 에서 vec[2]와 같이

사용할 수가 있다

 

 

 

 

이제 + 연산자를 구현해보자

 

operator+를 써준 뒤

반환값으로는 더해진 SimpleVector class자체를

반환해야하므로

SimpleVector<T>를 반환해준다

input으로는 더해야하는 상대(?)로 온

SimpleVector를 넣어준다

 

그런 다음 구현부를 보자

우선 SimpleVector내 array의 size만큼

새로운 result SimpleVector를 생성해준다

그다음 size만큼 for문을 돌면서

자기 자신과 더해야하는상대 simpleVector의

index 값을 더해주고 result에 넣어준다

 

그럼 main함수에서

vec1 + vec2를 해주면

vec1과 vec2의 각각의 요소들을 더한

vec3가 정상적으로 나오게 된다

 

위 operator overloading에서

input을 reference로 주는 이유는

copy를 막기 위해서

주로 사용하는 일종의 tradition이라고 한다

 

또, 일반적으로 연산자 operation이 끝났을 때

새로운 Object를 반환해주는 것이

+ operator의 convention이라고 한다

 

 

+= operator를 구현해보자

 

operator+=를 해준 뒤

return값으로는 SimpeVector<T>의 reference를

input으로는 상대편(?) SimpleVector의 reference를

그대로 받아온다

 

그런 다음 size만큼 array를 돌면서

상대편 array의 값을 더해준다음

자기 자신을 그대로 반환한다

이 점에서 새로운 SimpleVector를 반환하는

+와는 다르다고 볼 수 있다

 

또 하나 주목할점은

input인자로 받아오는 rhs에서

rhs.array에 접근하고있는걸

확인할 수 있는데

SimpleVector의 array는 private이다

 

이 operator+= 함수는

지금 class 밖에서 구현되고있는데

어떻게 private인 array에 접근이 가능한 것일까?

 

원칙상으로는 접근이 불가능한게 맞지만

현재 이 method가 SimpleVector내부에서

사용되고 있는 것이기 때문에

이런 경우 C에서 예외적으로 private한 instances에

접근할 수 있도록 허용해준다고 한다

 

 

 

operator++의 구현이다

 

++가 앞에 쓰여지는 걸

++ Prefix라고 한다

 

++ prefix의 경우

우선 ++ 연산을 먼저 하고 진행하란 뜻이고

뒤에 나올 ++ postfix의 경우는

우선 진행을 한 뒤 ++ 연산을 하란 뜻이다

 

아무튼 ++ prefix를 구현해주려면

operator++로 해준다음

return값으로는

더하기 연산이 된 자기 자신을

받아야하므로 SimpleVector reference를 받는다

 

그다음 size만큼 돌면서

array의 요소들을 한 개씩 증가시켜주면 된다

 

 

 

이번엔 ++ postfix이다

 

각각 1씩 증가시키는데 postfix기 때문에

증가는 시키지만 증가시키기 전의 값을 반환한다

 

prefix는 input이 없는데

postfix는 input으로 int를 넣어준다

딱히 큰 의미는 없고

prefix와 postfix를 구분하기 위함이다

 

prefix와 다른 점은

연산이 되기 전의 array를 반환해야하기때문에

새로운 SimpleVector를 생성해서 반환해야한다

 

구현부를 보면

temp라는 빈 SimpleVector를 생성한 다음

더하기 전 array요소를 temp에 넣어주고

array요소는 한 개씩 더해준다

 

그런 다음 temp를 반환한다


내용이 너무 길어져서

1편은 여기까지 ..

 

2편에는 남은

operator 구현방식과

non-member functions를

다룰 생각이다