728x90

황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!

https://search.shopping.naver.com/book/catalog/32436115747

 

C++ Programming : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

연산자 중복

+기호를 사용하여 숫자 더하기, 문자 더하기 등 다양한 행위를 할 수 있는데, 동일한 연산 혹은 기호(+)를 대상(피연산자)에 따라 서로 다르 의미로 해석하는 일종의 다형성(polymorphism)이다.

  • C++에서도 같은 이름의 함수를 여러 개 만들 수 있는 것이 함수 중복(function overloading)이라면, 피연산자에 따라 서로 다른 연산을 하도록 동일한 연산자를 중복해서 작성하는 것이 연산자 중복(operator overloading)
  • 간단히 + 연산자를 활용하는 예시를 보자
// 숫자 더하기
int a = 2, b = 3, c;
c = a+b;

// 두 개의 문자열 합치기
string a = "C", c;
c = a + "++" // c = C++

// 두 개의 배열 더하기
SortedArray a(2, 5, 9), b(3, 7, 10), c
c = a+b; // c = {2, 3, 5, 7, 9, 10} 정렬된 두 배열을 결합한 새로운 배열 생성

연산자 중복의 특징

1. C++ 언어에 본래 있는 연산자만 중복 가능

+, -, *, /, ==, !=, %, && 등 본래부터 있는 연산자에 새로운 의미 부여는 가능하지만, %%와 같이 새로운 연산자는 불가

 

2. 연산자 중복은 피연산자의 타입이 다른 연산을 새로 정의하는 것이다.

  • 기본 + 연산자의 피연산자는 모두 숫자
  • 따라서, + 연산자를 새로 중복하려면 '객체 + 수', '수 + 객체', '객체 + 객체'와 같이 정수나 실수가 아닌 객체나 값을 더하는 + 연산이어야 한다.

3. 연산자 중복은 함수를 통해 이루어진다.

  • 새로운 연산 처리를 수행하는 함수를 구현하는 것
  • 이 함수를 연산자 함수(operator function)이라고 한다.

4. 연산자 중복은 반드시 클래스와 관계를 가진다.

  • 중복된 연산자는 반드시 피연산자에 객체를 동반한다.
  • 그러므로 연산자 함수는 클래스의 멤버 함수로 구현하든지, 아니면 전역 함수로 구현하고 클래스에 프렌드 함수로 선언

5. 연산자 중복으로 피연산자의 개수를 바꿀 수 없다.

  • 이항 연산자 +에 대해, 피연산자가 1개 혹은 3개인 + 연산자로 중복할 수 없다.

6. 연산자 중복으로 연산의 우선순위를 바꿀 수 없다.

  • '2+5*6'의 경우 *연산자의 우선순위가 +보다 높아 먼저 계산된다.
  • 이런 연산의 순위를 바꿀 수 있는 연산자 중복은 불가능하다.

7. 모든 연산자가 중복 가능한 것은 아니다.


연산자 함수 선언과 연산자 함수 개요

연산자 함수는 2가지 방법으로 작성 가능하다.

  1. 클래스의 멤버 함수로 구현
  2. 외부 함수로 구현하고 클래스의 프렌드 함수로 선언
리턴타입 operator 연산자(매개변수리스트);

 

 

  • 연산자 함수 이름이 'operator' 키워드와 '연산자'로 구성된다는 점 외에는 보통의 함수 선언과 동일하다.
  • 또한, 외부 함수로 구현하는 것과, 클래스 멤버 함수로 구현하느냐에 따라 매개 변수 리스트는 달라진다.

 

외부 함수로 구현하고 클래스에 프렌드 함수로 선언하는 경우
Color operator + (Color op1, Color op2); // 외부 전역 함수
bool operator == (Color op1, Color op2); // 외부 전역 함수
...
class Color {
	...
	friend Color operator + (Color op1, Color op2); // 프렌드 선언
	friend bool operator == (Color op1, Color op2); // 프렌드 선언
};

 

클래스의 멤버 함수로 선언되는 경우
class Color {
	...
	Color operator + (Color op2); // 왼쪽 피연산자는 객체 자신이고 오른쪽 피연산자가 op2에 전달
	bool operator == (Color op2); // 왼쪽 피연산자는 객체 자신이고 오른쪽 피연산자가 op2에 전달
};
  • +==오른쪽 피연산자만 매개 변수 op2에 전달되고, 왼쪽 피연산자는 객체 자신이므로 매개 변수에 전달되지 않는다.

어떻게 구현되었든 +나 == 연산자는 아래와 같이 사용된다.

 

Color a(BLUE), b(RED), c;
c = a + b; // Color operator + (Color op2)나 Color operator + (Color op1, Color op2) 중 구현된 것을 호출한다.
if (a == b) { // bool operator == (Color op2)나 bool operator == (Color op1, Color op2) 중 구현된 것을 호출한다.
	...
}

이항 연산자 중복

  • 피연산자가 2개인 이항 연산자(binary operator)를 중복해보면 전체적으로 연산자 함수를 선언하고 구현하는 방법을 알 수 있을 것이다.
class Power {
	int kick;
	int punch;
public:
	Power(int kick = 0, int punch = 0) {
		this->kick = kick;
		this->punch = punch;
	}
};

산술 연산자를 대표하여 두 개의 Power 객체를 더하는 + 연산자를 선언하고 구현하는 과정을 보자

 

연산자 착안
  • 연산자를 만들기 전에 우선 +의 의미를 결정해야 한다.
  • + 연산의 의미를 정하는 것은 전적으로 개발자의 몫이다. 여기서는 kick과 punch를 더하는 것으로 정희한다.
Power a(3, 5), b(4, 6), c;

// + 연산자는 아래와 같이 사용한다.
c = a + b; // 두 개의 파워 개체를 더하는 + 연산

 

연산자 함수 선언
  • c++의 기본 + 연산에서는 피연산자에 수 이외의 값이 올 수 없기 때문에, 컴파일러는 a+b의 연산이 C++의 기본 더하기로 처리될 수 없음을 판단한다.
  • 이후, Power 클래스에 Power 객체를 더하는 + 연산자 함수가 새로 선언되어 있는지 찾고 이를 위해 컴파일러는 a+b 식을 아래와 같이 변형한다.
a . = ( b );

 

  • 이 식은 Power 객체 a의 멤버 함수 operator+()를 호출하며, b를 매개 변수로 넘겨주는 함수 호출이다.
  • 이 호철이 성공할 수 있도록 operator+() 함수를 클래스 멤버 함수로 선언한다.
class Power {
	Power operator+ (Power op2);
};
  • operator+() 함수는 리턴 타입을 Power로 하고, 더한 결과로 새로운 Power 객체를 리턴한다.

연산자 함수 구현
Power Power::operator+(Power op2) {
	Power tmp;
	tmp.kick = this->kick + op2.kick;
	tmp.punch = this->punch + op2.punch;
	return tmp;
}
  • 여기서 this는 Power 객체 a 자신에 대한 포인터
  • op2는 Power 객체 b를 전달받은 매개 변수
  • 따라서 this->kick + op2.kick;은 a의 kick과 b의 kick을 더하는 것이다.

 

Tip!!! 연산자 함수의 참조 매개 변수와 리턴 타입

  • 참조 매개 변수를 사용하면 매개 변수로 객체가 복사되지 않기에 효과적이나, 원본 객체 수정이 가능하므로 주의해야함
Power operator+ (Power op2);

// 아래와 같다.
Power operator+ (Power &op2);

 

#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+ (Power op2); // + 연산자 함수 선언
};

void Power::show() {
	cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}

Power Power::operator+(Power op2) { 
	Power tmp; // 임시 객체 생성
	tmp.kick = this->kick + op2.kick; // kick 더하기
	tmp.punch = this->punch + op2.punch; // punch 더하기
	return tmp; // 더한 결과 리턴
}

int main() {
	Power a(3,5), b(4,6), c;
	c = a + b; // 파워 객체 + 연산
	a.show();
	b.show();
	c.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();
	bool operator== (Power op2);  // == 연산자 함수 선언
};

void Power::show() {
	cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}

bool Power::operator==(Power op2) {
	if(kick==op2.kick && punch==op2.punch) return true;
	else return false;
}

int main() {
	Power a(3,5), b(3,5); // 2 개의 동일한 파워 객체 생성
	a.show();
	b.show();
	if(a == b) cout << "두 파워가 같다." << endl;
	else cout << "두 파워가 같지 않다." << endl;
}

 

+= 연산자 중복

  • 이 연산자에서 주목할 점은 아래와 같다.
    • (a+=b) += b;에서 += 연산자 함수가 객체 a를 리턴한다면 a의 복사본을 리턴한다.
    • 그러면 그 다음에 실행되는 +=b는 복사본 a에 연산되므로 원본에는 변함이 없다.
    • 따라서 += 연산자의 리턴 타입은 Power&로 하여 객체 a의 참조를 리턴하고, 이는 this를 이용하여 결과를 리턴한다는 점이다.
#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+= (Power op2); // += 연산자 함수 선언
};

void Power::show() {
	cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}

Power& Power::operator+=(Power op2) {
	kick = kick + op2.kick; // kick 더하기
	punch = punch + op2.punch; // punch 더하기
	return *this; // 합한 결과 리턴
}

int main() {
	Power a(3,5), b(4,6), c;
	a.show();
	b.show();
	c = a += b; // 파워 객체 더하기
	a.show();
	c.show();
}

 

실습해보기 : +연산자 작성 b = a + 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+ (int op2); // + 연산자 함수 선언
};

void Power::show() {
	cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}

Power Power::operator+(int op2) {
	Power tmp; // 임시 객체 생성
	tmp.kick = kick + op2; // kick에 op2 더하기
	tmp.punch = punch + op2; // punch에 op2 더하기
	return tmp; // 임시 객체 리턴
}

int main() {
	Power a(3,5), b;
	a.show();
	b.show();
	b = a + 2; // 파워 객체와 정수 더하기
	a.show();
	b.show();
}

 

단항 연산자 중복에 대해선 다음 게시물에서 알아보자..!

728x90

'Programming Language > C++' 카테고리의 다른 글

[C++] 상속  (1) 2023.12.06
[C++] 단항 연산자 중복과 프렌드로 구현하기  (2) 2023.12.06
[C++] 프렌드  (1) 2023.12.05
[C++] static 멤버  (0) 2023.12.05
[C++] 함수 중복  (0) 2023.12.04