[C++][OOP] Polymorphism - operator overloading

 

다형성(Polymorphism): 연산자 오버로딩

연산자 오버로딩: 객체 지향 프로그래밍의 유연성

객체 지향 프로그래밍 (OOP)에서 다형성 (Polymorphism)은 핵심 개념 중 하나이다. 다형성은 동일한 이름의 함수가 객체의 유형에 따라 다르게 동작하는 것을 의미한다. 오버로딩 (Overloading)은 다형성을 구현하는 방법 중 하나로, 동일한 이름의 함수에 여러 개의 정의를 부여하여 객체의 유형에 따라 적절한 함수가 호출되도록 한다.

C++에서는 연산자 오버로딩을 통해 연산자 (+, -, *, / 등)에 새로운 기능을 추가할 수 있다. 이는 사용자 정의 데이터 유형에 대해 기본 연산자를 사용할 수 있도록 하여 코드의 가독성과 직관성을 향상시킨다.



연산자 오버로딩 방법

C++에서 연산자 오버로딩은 다음 두 가지 방법으로 수행할 수 있다.

  1. Non-member 함수 접근: return_type operator@(a, b);
  2. 멤버 함수 접근: return_type a.operator@(b);

첫 번째 방법은 연산자 함수를 클래스 외부에서 정의하는 방식이고, 두 번째 방법은 클래스 내부에서 멤버 함수로 정의하는 방식이다. 두 방법의 주요 차이점은 연산자 함수가 클래스의 private 멤버에 접근할 수 있는지 여부이다. 멤버 함수는 클래스의 private 멤버에 접근할 수 있지만, non-member 함수는 접근할 수 없다(그래서 friend 이용).



연산자 오버로딩 예시: << 연산자

<< 연산자는 일반적으로 출력 스트림에 데이터를 삽입하는 데 사용된다. Complex 클래스를 정의하고 << 연산자를 오버로딩하여 복소수를 출력 스트림에 삽입할 수 있도록 해 보자.

C++
class Complex {
  int* m_r; // 실수 부분
  int* m_i; // 허수 부분
public:
  friend ostream& operator<<(ostream& o, Complex c);
};

ostream& operator<<(ostream& o, Complex c) {
  o << *c.m_r << (*c.m_i < 0 ? "" : "+") << *c.m_i << "j";
  return o;
}

위 코드에서 operator<< 함수는 Complex 객체를 인자로 받아, 실수 부분과 허수 부분을 출력 스트림에 삽입한다.

example code



연산자 오버로딩 예시: [] 연산자

[] 연산자는 배열의 요소에 접근하는 데 사용된다. Vector 클래스를 정의하고 [] 연산자를 오버로딩하여 동적 배열의 요소에 접근할 수 있도록 해 보자.

C++
class Vector {
  int* m_data; // 동적 배열에 대한 포인터
  int m_size; // 배열 크기
public:
  int& operator[](int index);
};

int& Vector::operator[](int index) {
  if (index >= m_size) {
    cout << "Error: index out of bound";
    exit(0);
  }
  return m_data[index];
}

위 코드에서 operator[] 함수는 인덱스를 인자로 받아, 해당 인덱스의 배열 요소를 반환한다.

example code(default value is 0)




L-value와 R-value

L-value는 메모리 위치를 나타내는 값이고, R-value는 메모리 위치에 저장된 값 자체를 나타내는 값이다. L-value는 대입 연산자의 왼쪽과 오른쪽 모두에 나타날 수 있지만, R-value는 오른쪽에만 나타날 수 있다.

L-value vs R-value



연산자 오버로딩 예시: = 연산자

= 연산자는 변수에 값을 대입하는 데 사용된다. Complex 클래스를 정의하고 = 연산자를 오버로딩하여 복소수 객체를 다른 복소수 객체에 대입할 수 있도록 해 보자.

C++
class Complex {
  int* m_r; // 실수 부분
  int* m_i; // 허수 부분
public:
  Complex& operator=(const Complex& c);
};

Complex& Complex::operator=(const Complex& c) {
  if (this == &c) {
    return *this;
  }
  delete m_r;
  delete m_i;
  m_r = new int(*c.m_r);
  m_i = new int(*c.m_i);
  return *this;
}

위 코드에서 operator= 함수는 Complex 객체를 인자로 받아, 현재 객체의 멤버 변수 값을 인자로 받은 객체의 멤버 변수 값으로 변경한다.

example code




마치며

이번 포스팅에서는 연산자 오버로딩, L-value와 R-value에 대해 알아보았다. 연산자 오버로딩은 객체 지향 프로그래밍의 유연성을 향상시키는 데 중요한 역할을 한다. 다음 시간에는 Inheritance(상속)에 대해 알아보도록 하겠다.

hyeon_B

안녕하세요! AI 기술을 이용해 더 나은 세상을 만들어 나가고 싶은 과기원생 Hyeon이라고 합니다. 저는 앞으로 인공지능 시대에는 지식을 '활용'하는 능력이 중요해질 것이라고 생각합니다. 대부분의 일들은 인공지능이 뛰어난 모습을 보이지만, 인공지능은 데이터로 부터 연관관계를 학습하기 때문에 지식들을 새로 통합해서 활용하는 능력이 부족합니다. 인공지능이 뉴턴 전에 만들어졌다면 사과가 떨어지는 이유에 대답하지 못했을 것이고, 아인슈타인 전에 만들어졌다면 중력이 어떻게 생기는지 설명하지 못했을 것입니다. 따라서 앞으로 우리는 '본질'을 탐구하고 그 본질로부터 다른 곳에 적용하며 인공지능을 현명하게 활용해야 할 것입니다. 함께 인공지능 시대를 준비합시다!

댓글 쓰기

다음 이전

POST ADS1

POST ADS 2