출처 => C++ How to Program (Detitel / Prenticehall) / 현재 그리고 미래지향적인 C++ 프로그래밍(장석우, 임정목 / 비앤씨에듀케이션)
https://beomnaegol.tistory.com/entry/C-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%98%A4%EB%B2%84%EB%A1%9C%EB%94%A9-3-%EC%A0%84%EC%9C%84%EC%A6%9D%EA%B0%90%EA%B3%BC-%ED%9B%84%EC%9C%84%EC%A6%9D%EA%B0%90
http://blog.daum.net/coolprogramming/73
연산자 중복의 정의
▶ 연산자 중복이랑 C++에서 제공하는 기본 타입이 아닌 클래스 타입(사용자가 정의하는 타입)에도 연산자를 사용할 수 있도록 하는 문법이다.
▶ 예를 들어,
cout<<2+3<<endl;
// 5
위의 소스코드는 컴파일이 가능하지만,
cout<<빨간색+노란색<<endl;
// 컴파일 오류!
이는 당연히 오류가 생긴다.
우리는 직관적으로 빨간색과 노란색을 섞으면 주황색이 나온다는 것을 알지만 컴파일러는 이런 사실을 알고 있지 않기 때문이다.
▶ 따라서 컴파일러 내부에 정의되어 있지 않은 자료형의 연산도 제공할 수 있도록 하여 코드의 직관성, 가독성, 그리고 편의성을 제공하고자 만든 문법이 연산자 중복이다.
연산자 중복의 특징은 다음과 같다.
▶ C++에 본래 있는 연산자만 가능하다. **나 %%와 같은 기괴한 형태의 연산자는 불가능!
▶ 연산자는 함수 형태로 구현이 된다.
▶ 반드시 클래스와 관계를 가져야 한다.
▶ 모든 연산자가 중복 가능하지 않는다. 가령, ::는 범위를 지정해주는 연산자이기 때문에 연산자 중복으로서 기능을 담당할 수가 없다.
▶ 연산자는 크게 2가지의 방법으로 구현이 가능하다.
1. 외부 함수로 구현하고 클래스에 프랜드 함수로 선언
2. 클래스의 멤버함수로 구현
1. 외부 함수로 구현하고 클래스에 프랜드 함수로 선언하는 예제
#include<iostream>
using namespace std;
class Rect {
private:
int width, height;
public:
Rect(int width=0, int height=0) {
this->width = width;
this->height = height;
}
void show();
friend Rect operator -(Rect a, Rect b);
};
Rect operator-(Rect a, Rect b) {
Rect c;
c.width = a.width - b.width;
c.height = a.height - b.height;
return c;
}
void Rect:: show() {
cout << "width :" << width
<< "," << "height" << height<<endl;
}
void main() {
Rect a(5, 8), b(1, 3), c;
c = a - b;
c.show();
}
2. 클래스의 멤버함수로 연산자를 구현하는 예제
#include<iostream>
using namespace std;
class Rect {
private:
int width, height;
public:
Rect(int width = 0, int height = 0) {
this->width = width;
this->height = height;
}
Rect operator +(Rect r);
void show();
};
Rect Rect::operator +(Rect r) {
Rect c;
c.width = this->width + r.width;
c.height = this->height + r.height;
return c;
}
void Rect::show() {
cout << "width:" << width
<< "," << "height:" << height << endl;
}
void main() {
Rect a(5, 8);
Rect b(1, 5);
Rect c;
c = a + b;
c.show();
}
외부함수로 구현한 연산자와 클래스의 멤버함수로 구현한 연산자의 차이점
▶ 두 가지의 방법이 약간 다르다. 이를 설명하자면 다음과 같다.
▶ 위의 예시와 비교를 해보기에 앞서 1번 예시는 외부 함수로 구현하고 클래스에 프랜드 함수로 선언하는 방법이고, 2 번 예시는 클래스의 멤버함수로 연산자를 구현하는 예제임을 다시 한 번 강조한다.
▶ 먼저 위의 예시이다.
Rect operator-(Rect a, Rect b) {
Rect c;
c.width = a.width - b.width;
c.height = a.height - b.height;
return c;
}
▶ Rect클래스의 연산자인 -, 그리고 그 연산자의 사용되는 객체 a와 b. Rect 클래스의 또 다른 예시인 c는 a의 가로 세로를 b의 가로 세로와 합한 값이다.
▶ 위의 코드는 직관적이다. a의 가로 세로, b의 가로 세로를 합하고 그 합한 결과인 c라는 객체를 return 한다. operator 연산자가 Rect형이니 c로 return을 할 수 있다.
▶ 그 다음은 2번 예제의 소스코드이다.
Rect Rect::operator +(Rect r) {
Rect c;
c.width = this->width + r.width;
c.height = this->height + r.height;
return c;
}
▶ 1번 예시는 Rect 클래스의 객체 a ,b가 다 있었던 반면에 이 소스코드는 r이라는 객체밖에 없다. 왜 그럴까?
▶ 위의 그림이 답해주고 있다. 클래스의 멤버함수로 구현하는 경우(2번 예시), 클래스 자신이 이미 1개의 인자 역할을 하기 때문에 1번처럼 2개로 객체를 지정하면 이 연산자 함수에 매개변수가 너무 많습니다는 오류 메시지가 발생하게 된다. 따라서 클래스의 멤버함수로 선언할 때는 위와 같이 해줘야 한다.
전위 연산자와 후위 연산자
▶ 조건문을 쓸 때 흔히 ++나 --를 사용한다. 이를 증감연산자라고 부르는데, 변수의 앞에 붙으면 전위증감, 뒤에 붙으면 후위증감이라고 부른다. 이는 연산자 오버로딩에서도 똑같이 적용되지만 구현을 하기 위해서는 특별한 법칙을 알아야 한다.
▶ 먼저 전위 연산자이다.
#include<iostream>
using namespace std;
class Power {
int kick;
int punch;
public:
Power(int kick = 0, int punch = 0) {
this->kick = kick;
this->punch = punch;
}
void show();
Power operator++();
};
void Power::show() {
cout << "kick=" << kick
<< "," << "punch=" << punch << endl;
}
Power Power::operator++() {
kick++;
punch++;
return *this;
}
void main() {
Power a(3, 5), b;
a.show();
b.show();
b = ++a;
a.show();
b.show();
}
▶ 다음은 후위 연산자이다.
#include<iostream>
using namespace std;
class Power {
int kick;
int punch;
public:
Power(int kick = 0, int punch = 0) {
this->kick = kick;
this->punch = punch;
}
void show();
Power operator++(int x); //후위 ++연산자 함수 선언
};
void Power::show() {
cout << "kick=" << kick
<< "," << "punch=" << punch << endl;
}
Power Power::operator++(int x) {
Power tmp = *this;
//증가 이전 객체 상태를 저장
kick++;
punch++;
return tmp;//증가 이전의 객체 return
}
void main() {
Power a(3, 5), b;
a.show();
b.show();
b =a++;//후위 연산자 사용
a.show();//a의 파워 1증가
b.show();//b는 a가 증가되기 이전의 상태를 가짐
}
▶ 이 두 연산자 역시 차이점이 존재한다. 전위 연산자 함수와 후위 연산자 함수를 비교해보자.
//전위 연산자
Power Power::operator++() {
kick++;
punch++;
return *this;
}
▶ kick과 punch를 각각 1만큼 증가시킨 뒤에, 그 증가가 된 객체를 return하는 것을 볼 수 있다.
//후위 연산자
Power Power::operator++(int x) {
Power tmp = *this;
//증가 이전 객체 상태를 저장
kick++;
punch++;
return tmp;//증가 이전의 객체 return
}
▶ 그와 달리, 후위 연산자는 증가 이전의 객체를 tmp라는 Power 클래스의 또다른 객체에 저장하고, 증가를 시킨 뒤에 tmp를 return함을 알 수 있다.
'💻 개인공부 💻 > C | C++' 카테고리의 다른 글
[C++] 상속(Inheritance) - 2 (feat. 가상 함수와 추상클래스) (0) | 2020.06.20 |
---|---|
[C++] 상속(Inheritance) - 1 (feat. 개념, 상속 접근 지정자) (0) | 2020.06.19 |
[C++] 프랜드 함수 (0) | 2020.06.19 |
[C++] 생성자와 소멸자 (0) | 2020.06.18 |
[C++] 포인터 변수 (feat. * / & / **) (0) | 2020.06.17 |