-
c++ operator overloading대학/자료구조 2022. 10. 16. 22:19
기초 타입 변수의 경우 a + b 같은 연산자가 동작하는데 아무런 의심도 없이 사용했다.
하지만, 직접 정의한 클래스의 연산을 할 때, c1 + c2 같은 연산을 하면 에러가 발생한다.
이런 경우에 클래스에서 연산자 오버로딩 기법을 사용하면 된다.
설명을 위해서 이 포스팅에선 아래의 MyDoubleVector 클래스를 간단하게 정의하고 시작하겠다.
class MyDoubleVector { public: ... private: double *data; // member variable: data container size_t max_capacity; // member variable: max qty of data size_t used; // member variable: counting data qty };
- Assignment operator overloading
첫 번째는 할당 연산자 (=) 오버로딩 방법이다.
MyDoubleVector &MyDoubleVector::operator=(const MyDoubleVector &v) { if (this != &v) { if (max_capacity != v.max_capacity) { delete[] data; data = new double[v.max_capacity]; max_capacity = v.max_capacity; } copy(v.data, v.data + v.used, data); used = v.used; } return *this; }
v1 = v2라고 한다면, 이 연산자 오버로딩에서는 this는 v1을 가리키게 되고, &v는 v2를 가리키게 된다.
그래서 처음에 v1 = v1같은 일을 방지하기 위해서 this(v1)와 &v(v2)를 검사한다.
둘이 다르다면, 기존 공간을 delete로 해제한 후 new로 새로운 공간을 할당한다.
그 후 *this를 리턴하여 값을 받을 수 있도록 해준다.
이런식으로 하면 새로운 객체가 리턴되는 효과를 갖기 때문에 v1 = v2 = v3 같이 연속된 연산도 처리할 수 있다.
- Binary operator overloading
두 번째 방법은 이진 연산자 (+, -, *, /) 오버로딩 방법이다.
MyDoubleVector MyDoubleVector::operator+(const MyDoubleVector &v) { assert(used == v.used); MyDoubleVector result = *this; for (int i = 0; i < used; i++) { result.data[i] = data[i] + v.data[i]; } return result; }
v1 + v2라고 한다면, 이 연산자 오버로딩에서는 this는 v1을 가리키게 되고, &v는 v2를 가리키게 된다.
그 다음 같은 클래스 타입으로 result를 생성하게 되는데, 새로운 클래스를 생성하지 않고, *this의 값을 변경하게 된다면,
연산의 결과가 v1의 값을 바꾸게 되기 때문에, 새로운 result 객체를 생성하고 여기에서 연산을 수행하는 것이다.
마찬가지로 이렇게 하면, 새로운 객체가 리턴되기 때문에 v1 + v2 + v3 같이 연속된 연산도 처리할 수 있다.
Assignment operator와 다르게 리턴 타입이 MyDoubleVector & 가 아니라 그냥 MyDoubleVector 인 이유는,
리턴하는 변수가 포인터 타입이 아니라 그냥 MyDoubleVector 타입이기 때문이다.
- Unary operator overloading
세 번째 방법은 단항 연산자 (-) 오버로딩 방법이다.
MyDoubleVector MyDoubleVector::operator-() { MyDoubleVector result = *this; for (int i = 0; i < used; i++) { result.data[i] = data[i] * -1; } return result; }
-v1 라고 한다면, 이 연산자 오버로딩에서는 this가 v1을 가리키게 된다.
나머지는 Binary operator overloading과 같은 방식으로 동작한다.
- Compound assignment operator overloading
네 번째 방법은 복합 할당 연산자 (+=, -=, *=, /=) 오버로딩 방법이다.
void MyDoubleVector::operator+=(const MyDoubleVector &v) { assert(used + v.used <= max_capacity); copy(v.data, v.data + v.used, data + used); used += v.used; }
v1 += v2 라고 한다면, 이 연산자 오버로딩에서는 this는 v1을 가리키게 되고, &v는 v2를 가리키게 된다.
단, 이번에는 바로 멤버 변수에 접근하는 방법을 사용해 보았다. (this->data 대신 그냥 data 사용)
위와 다른 점이라면 리턴 타입이 없다는 것인데, 그 이유는 v1 += v2의 연산 결과를 v1에 저장하기 때문에
멤버 변수의 값을 함수 내부에서 변경하면 바로 끝나기 때문이다.
단, 새로운 객체를 리턴하지 않기 때문에 v1 += v2 += v3 같은 연속된 연산은 처리가 불가능하다.
(논리적으로 저런 연산은 없기도 하고...)
- Comparison operator overloading
다섯 번째 방법은 비교 연산자 (==, !=) 오버로딩 방법이다.
bool MyDoubleVector::operator==(const MyDoubleVector &v) { if (used != v.used) { return false; } for (int i = 0; i < used; i++) { if (data[i] != v.data[i]) { return false; } } return true; }
v1 == v2 라고 한다면, 이 연산자 오버로딩에서는 this는 v1을 가리키게 되고, &v는 v2를 가리키게 된다.
단, 이번에도 바로 멤버 변수에 접근하는 방법을 사용해 보았다. (this->data 대신 그냥 data 사용)
이번에는 리턴 타입이 bool 타입인데, 말 그대로 참/거짓만 판단하면 되기 때문이다.
- Etc...
double MyDoubleVector::operator[](const unsigned int idx) { assert(idx < used); return data[idx]; } void MyDoubleVector::operator()(const double x) { for (int i = 0; i < used; i++) { data[i] = x; } }
산술 연산자 말고도 괄호나 대괄호 같은 연산자도 오버로딩 가능하다.
상황에 맞는 기능으로 오버로딩 하여 사용하면 좋을 거 같다.
'대학 > 자료구조' 카테고리의 다른 글
Linked list (0) 2022.10.17 Dynamic array (0) 2022.10.17 Static array (0) 2022.10.16 c++ class, parameter types (0) 2022.10.16 Pre, Postcondition (0) 2022.10.15