본문 바로가기
CODING/C++ STUDY

C++ 독학 9일차 - 오버로딩

by pharmerci 2021. 7. 29.
728x90

c에서는 +,-,==,[] 이런 기본 연산자는 c언어에 정의된 데이터 타입에만 사용이 가능했다.

그러니까

int a=1;

int b=2;

int c;

c=a+b;

이런식으로 정수형이나 float형 같은 것들에만 쓸 수 있고

char a="h";

char b="i";

char c[2];

c=a+b;

뭐 이런거는 안된다. c는 hi가 될 수 없다는 것이다

 

그런데 C++에서는 사용자 정의 연산자가 가능하다. 단 ::이랑 .이랑 .* 이거 빼고

 

기본 연산자들을 직접 사용자가 정의하는 것을 연산자를 오버로딩 한다고 한다.

 

 

 

 


==연산자 오버로딩

연산자 오버로딩을 위해서는

(리턴타입) operator (연산자) (연산자가 받는 인자)

이런 형태로 함수를 제작하면 된다.

 

두 문자열이 같은지 다른지 조사하는 함수를 만들 때

bool operator==(mystring& str);

이렇게 만든다.

 

그리고 bool mystring::operator==(mystring& str) {

return !compare(str);

}

 

이렇게 함수를 만들면 된다. compare이라는 함수는 이전 글에서 만들었기 때문에 참고하면 된다.

!compare(str)을 리턴하는 이유는 

compare함수에서 str과 *this가 같으면 0을 리턴하게 했는데 operator==은 같으면 true를 리턴해야 하기 때문이다.

그러니까 반대로 작동하게 !를 붙여준 것이다.

 

참고로 compare 함수는 아래와 같다.

 


복소수 클래스 만들기

mystring에서 벗어날 수 있을 것 같다. 너무 길어서 정말 감당이 안되는 클래스..

복소수를 다루는 클래스인데 a+bi 이런 형태가 복소수이지 않은가!!

그래서 실수부랑 허수부로 나눠서 복소수 클래스를 만들면 된다.

 

이것은 오버로드를 이용하지 않은 클래스.

a+b/c+d 표현하는데 굉장히 복잡하고 사용자 입장에서 이게 뭘 하려는 코드지? 싶을 것이다.

 

 

 

이렇게! 오버로드를 이용해서 함수를 다음과 같이 선언해주자는 것이다.

모두 complex& 가 아니라 complex를 리턴하고 있다.

그리고 operate+같은 모든 함수들은 내부에서 읽기만 수행되고 값이 안바뀌는 인자들을 갖는다.

값이 바뀌지는 않고 연산만 각각 수행되기 때문이다. 이럴땐 함수 선언할 때 const로 선언해주기

 

 


대입 연산자 함수

complex& operator=(const complex& c);

 

이렇게 함수를 구현한다. 아까 사칙연산 함수들과 다르게 여기서는

자기 자신을 가리키는 레퍼런스 complex&를 리턴한다.

 

왜그러냐면

a=b=c;

코드에서 b=c가 b를 리턴해야 a=b가 수행될 수 있기 때문이다.

 

이 때 complex&를 리턴하는 이유는 대입 연산 후에 불필요한 복사를 방지하기 위해서이다.

 

operator= 함수를 만들면!?

 

이렇게 만들어진다. 그런데 operator=를 굳이 안만들어도 잘 작동하긴 한다.

왜냐하면 컴파일러 차원에서 디폴트 대입 연산자를 지원하고 있어서 그렇다.

하지만 이전에 공부했는데 깊은 복사가 필요한 경우(동적 메모리 관리하는 포인터 복사) 대입 연산자 함수를 다시 만들어야 한다.

 

+=, -=, *=, /=같은 연산자도 만들어줄 수 있다.

형태는 complex& operator+=(const complex& c);

이런 느낌으로 연산자를 만들면 되고 함수 만드는 것은 아까 만든 + - * / 를 이용해서 만들면 되므로

쉽게 만들 수 있다.

 

그런데 연산자 오버로딩을 사용할 때 방금 얘기한 +=, -=, *=, /=이걸 따로 만들어주지 않으면 +=를 자신있게 사용하기는 어렵다.

다 개별적으로 정의해야 한다.

 

 

 

 


friend

friend는 클래스 내부에서 다른 클래스나 함수를 friend로 정의한다. friend로 정의된 클래스, 함수는 private로 정의된 변수나 함수에 접근할 수 있다.

 

friend를 사용하는 모습이다. 주석에 설명이 써져있다.

 

 


입출력 연산자 오버로딩

지금까지 우리가 뭔가 출력할 때 쓰던게

std::cout << a;

이런거였는데 사실 이것은 std::cout.operator<<(a) 여기에서 나온거였다.

 

std::cout라는 객체에 멤버함수 operator<<가 정의되어 있어서 a를 호출하게 된다는 것이다.

그런데 std::cout는 정수형 실수형 문자열까지 자유자재로 호출된다. 그 이유는 operator<< 함수가

오버로딩 되어있기 때문이다.

 

iostream 헤더파일 내용을 보면 ostream이라는 클래스 안에 많은 종류의 operator<<를 정의하고 있다. 그래서 우리는 형식에 관계없이 자유롭게 출력을 이용하고 있었던 것이다.

ostream 클래스에 operator<<멤버 함수를 추가하는 것은 불가능하다. 왜냐하면 표준 헤더파일의 내용을 수정해야 하기 때문이다. 그래서 ostream에다가 complex 객체를 오버로딩하는 operator<< 함수 추가 못한다!!

 

하지만 ostream 클래스 객체와 complex 객체 두개를 인자로 받는 전역함수를 정의하는 것은 가능할 것 같다. 이 때 friend 함수도 같이 이용해주면 클래스의 private 멤버 변수들에도 접근 가능하다. 하지만 무분별하게 friend를 남발하는 것은 좋지 않다. 왜냐하면 friend는 해당 함수나 클래스에 모든 private 멤버 함수, 변수를 공개해버리기 때문이다.

 

 

 


동등한 객체 사이에서의 이항 연산자는 외부함수로 오버로딩 하는 것이 좋다.

두개 객체 사이의 이항연산자이지만 한 객체만 값이 바뀌는 등의 동등하지 않은 이항연산자는 멤버함수로 오버로딩 하는 것이 좋다.

단항 연산자는 멤버함수로 오버로딩 하는 것이 좋다 (ex. ++, --)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

728x90