[C++] 연산자 오버로딩(overloading)

·2023년 8월 21일
0

C++

목록 보기
9/17
post-custom-banner

연산자 오버로딩

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

bool operator==(myString& str);

bool myString::operator==(myString& s)
{
	// myString에서 만든 함수로 s와 같으면 0을 리턴함
    // 같을 때 true가 필요하므로 !를 써서 값을 뒤집음
    return !compare(s); 
}

기존에 만든 myString에 위 함수를 만든 후 아래와 같이 main 함수 실행

int main()
{
	myString str1("a word");
	myString str2("sentence");
	myString str3("sentence");

	if (str1 == str2)
		std::cout << "str1 와 str2 같다." << std::endl;
	else
		std::cout << "st1 와 str2 는 다르다." << std::endl;

	if (str2 == str3)
		std::cout << "str2 와 str3 는 같다." << std::endl;
	else
		std::cout << "st2 와 str3 는 다르다" << std::endl;
}

실행 결과
st1 와 str2 는 다르다.
str2 와 str3 는 같다.


복소수(Complex number) 클래스 만들기

#include <iostream>

class Complex 
{
private:
    double real, img;

public:
    Complex(double real, double img) : real(real), img(img) {}
    Complex(const Complex& c) { real = c.real, img = c.img; }

    Complex operator+(const Complex& c) const;
    Complex operator-(const Complex& c) const;
    Complex operator*(const Complex& c) const;
    Complex operator/(const Complex& c) const;

    void println() { std::cout << "( " << real << " , " << img << " ) " << std::endl; }
};

Complex Complex::operator+(const Complex& c) const 
{
    Complex temp(real + c.real, img + c.img);
    return temp;
}

Complex Complex::operator-(const Complex& c) const 
{
    Complex temp(real - c.real, img - c.img);
    return temp;
}

Complex Complex::operator*(const Complex& c) const 
{
    Complex temp(real * c.real - img * c.img, real * c.img + img * c.real);
    return temp;
}

Complex Complex::operator/(const Complex& c) const 
{
    Complex temp(
        (real * c.real + img * c.img) / (c.real * c.real + c.img * c.img),
        (img * c.real - real * c.img) / (c.real * c.real + c.img * c.img));
    return temp;
}

int main() 
{
    Complex a(1.0, 2.0);
    Complex b(3.0, -2.0);

    Complex c = a * b;

    c.println();
}

실행 결과
( 7 , 4 )

값을 리턴하는 연산자 함수

// 연산자 함수 모두 Complex&가 아닌 Complex를 리턴해야 하는 이유
Complex& operator+(const Complex& c) 
{
  real += c.real;
  img += c.img;
  return *this;
}

Complex a = b + c + b;
// 사용자의 의도는 2 * b + c를 a에 대입하는 것이지만
// Complex&로 리턴하게 되면 
// (b.plus(c)).plus(b) 중 b.plus(c)를 하면서 b에는 (b+c)가 들어가게 되고,
// 거기에 다시 plus(b)를 하게 되면 (b+c) + (b + c)가 됨
// 즉, 2 * b + 2 * c가 되어 사용자의 의도와 값이 달라지게 됨

대입 연산자 함수

&를 리턴하는 연산자 함수

// 대입 연수는 위의 사칙연산 함수와 다르게 자기 자신을 가리키는 &를 리턴해야 함
a = b = c;
// 위와 같은 코드에서 b = c;가 b를 리턴해야만 a = b;가 성공적으로 수행되기 때문
// 대입 연산 이후 불필요한 복사를 방지하기 위해 Complex& 타입으로 반환

Complex& Complex::operator=(const Complex& c)
{
  real = c.real;
  img = c.img;
  return *this;
}

operator=를 만들지 않아도 잘 작동함
-> 컴파일러 차원에서 디폴트 대입 연산자를 지원하기 때문
디폴트 복사 생성자와 마찬가지로 디폴트 대입 연산자 역시 얕은 복사를 수행함
따라서, 깊은 복사가 필요한 클래스의 경우 대입 연산자 함수를 만들어주어야 함
(예) 클래스 내부에 동적 할당되는 메모리를 관리하는 포인터가 있는 경우

+=, -=, *=, -=

Complex& operator+=(const Complex& c);
Complex& operator-=(const Complex& c);
Complex& operator*=(const Complex& c);
Complex& operator/=(const Complex& c);
Complex& Complex::operator+=(const Complex& c) 
{
  (*this) = (*this) + c;
  return *this;
}
Complex& Complex::operator-=(const Complex& c) 
{
  (*this) = (*this) - c;
  return *this;
}
Complex& Complex::operator*=(const Complex& c) 
{
  (*this) = (*this) * c;
  return *this;
}
Complex& Complex::operator/=(const Complex& c) 
{
  (*this) = (*this) / c;
  return *this;
}

두 문장의 차이

Some_Class a = b;  // ①

Some_Class a;  // ②
a = b;

① a의 '복사 생성자'가 호출
② a의 기본 생성자 호출 -> 대입 연산자 함수가 실행


문자열로 'Complex' 수와 덧셈하기

Complex Complex::operator+(const char* str) 
{
  // 입력 받은 문자열을 분석하여 real 부분과 img 부분을 찾아야 한다.
  // 문자열의 형태 : "[부호](실수부)(부호)i(허수부)"
  // 이 때 맨 앞의 부호는 생략 가능 (생략시 + 라 가정)

  int begin = 0, end = strlen(str);
  double str_img = 0.0, str_real = 0.0;

  // 먼저 가장 기준이 되는 'i' 의 위치를 찾는다.
  int pos_i = -1;
  for (int i = 0; i != end; i++) 
  {
    if (str[i] == 'i') 
    {
      pos_i = i;
      break;
    }
  }

  // 만일 'i' 가 없다면 이 수는 실수 뿐임
  if (pos_i == -1) 
  {
    str_real = get_number(str, begin, end - 1);

    Complex temp(str_real, str_img);
    return (*this) + temp;
  }

  // 만일 'i' 가 있다면,  실수부와 허수부를 나누어서 처리
  str_real = get_number(str, begin, pos_i - 1);
  str_img = get_number(str, pos_i + 1, end - 1);

  if (pos_i >= 1 && str[pos_i - 1] == '-') str_img *= -1.0;

  Complex temp(str_real, str_img);
  return (*this) + temp;
}

double Complex::get_number(const char *str, int from, int to) const 
{
  bool minus = false;
  if (from > to) return 0;

  if (str[from] == '-') minus = true;
  if (str[from] == '-' || str[from] == '+') from++;

  double num = 0.0;
  double decimal = 1.0;

  bool integer_part = true;
  for (int i = from; i <= to; i++) 
  {
    if (isdigit(str[i]) && integer_part) 
    {
      num *= 10.0;
      num += (str[i] - '0');
    } 
    else if (str[i] == '.')
      integer_part = false;
    else if (isdigit(str[i]) && !integer_part) 
    {
      decimal /= 10.0;
      num += ((str[i] - '0') * decimal);
    } 
    else
      break;  // 그 이외의 이상한 문자들이 올 경우
  }

  if (minus) num *= -1.0;

  return num;
}
post-custom-banner

0개의 댓글