728x90

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

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

 

C++ Programming : 네이버 도서

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

search.shopping.naver.com

단항 연산자

단항 연산자(unary operator)란 앞에서 본 이항 연산자와는 다르게 피연산자가 하나이다. 위치에 따라 전위 연산자(prefix operator)와 후위 연산자(postfix operator)로 나뉜다.

전위 연산자 : !op, ~op, ++op, --op ....
후위 연산자 : op++, op-- ....

 

전위 ++ 연산자 중복

위 그림에서 return 타입은 Power&

#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; // 변경된 객체 자신(객체 a)의 참조 리턴
}

int 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();
	bool operator! (); // ! 연산자 함수 선언
};

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

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

int main() {
	Power a(0,0), b(5,5);
	if(!a) cout << "a의 파워가 0이다."  << endl; // ! 연산자 호출
	else cout << "a의 파워가 0이 아니다." << endl;
	if(!b) cout << "b의 파워가 0이다." << endl; // ! 연산자 호출
	else cout << "b의 파워가 0이 아니다." << endl;
}

 

후위 ++ 연산자 중복
  • 전위 연산자와 후위 연산자를 구분하기 위해 후위 연산자 함수는 매개 변수를 가지도록 선언한다.
Power operator++(); // 전위
Power operator++(int x); // 후위, 매개 변수 x에는 의미 없는 값이 전달되므로 무시해도 된다.

#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; // 증가 이전 객체 상태 리턴
}

int main() {
	Power a(3,5), b;
	a.show();
	b.show();
	b = a++; // 후위 ++ 연산자 사용
	a.show(); // a의 파워는 1 증가됨
	b.show(); // b는 a가 증가되기 이전 상태를 가짐
}

 

// 다양한 이항 연산자를 클래스의 연산자 멤버 함수로 선언한 예

Power operator + (Power op2)     ==> Power operator + (Power& op2)
bool operator != (Power op2)
Power& operator += (Power op2)
Power operator + (int b)
bool operator > (int b)
Power& operator += (int b)

// 다양한 단항 연산자를 클래스의 연산자 멤버 함수로 선언한 예
bool operator ! ()
Power operator ~ ()
Power& operator ++ ()
Power operator ++ (int x)
Power& operator -- ()
Power operator -- (int x)

프렌드를 이용한 연산자 중복

  • 지금까지는 클래스의 멤버 함수로 작성하였지만, 연산자 함수는 클래스 바깥의 외부 전역 함수로도 작성 가능
  • 연산자 함수를 클래스에서 friend로 취하여 클래스 멤버를 자유롭게 접근할 수 있게 한다.

 

2+a를 위한 + 연산자 함수 작성
Power a(3, 4), b;
b = 2+a;

// 지금까지는 아래와 같이 변형한다.
2 . + (a)
  • 그러나 2가 객체가 아니므로, 위의 변형식은 잘못된 문장이다.
  • 즉, 첫 번째 피연산자가 객체가 아닌 경우 아래와 같이 변형한다.
+ (2, a)

  • 이처럼 연산자 함수를 오직 외부 함수로만 작성해야 하는 경우가 있다.
외부 연산자 함수의 프렌드 선언
  • operator+(int, Power) 연산자 함수에는 하나의 걱정이 있다.
  • 함수 내에서 Power의 private 멤버인 kick과 punch를 자유롭게 접근하고 있기 때문이다.
  • 이를 해결하기 위하여 kick과 punch를 public으로 선언하게 된다면 캡슐화 원칙을 무너뜨리는 꼴이다.
  • 따라서, friend 함수를 사용하면 깔끔하게 해결된다.
#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();
	friend Power operator+(int op1, Power op2); // 프렌드 선언
};

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

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

int main() {
	Power a(3,5), b;
	a.show();
	b.show();
	b = 2 + 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();
	friend Power operator+(Power op1, Power op2); // 프렌드 선언
};

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

Power operator+(Power op1, Power op2) {
	Power tmp; // 임시 객체 생성
	tmp.kick = op1.kick + op2.kick; // kick 더하기
	tmp.punch = op1.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();
}

 

잊지 말아야 될 것이 하나의 연산자 함수를 멤버 함수와 프렌드 함수로 동시에 구현할 수 없다!!

 

단항 연산자 ++를 프렌드로 작성하기
  • 단항 연산자 ++를 변경할 때 매우 중요한 점이 있다.
  • 두 연산자 모두 Power& op를 사용하며, 전위 연산자의 경우 참조를 리턴한다는 점이다..!
  • Power& op의 참조 매개 변수를 사용함으로써 op는 객체 a를 참조하게 되어 op 객체를 변경하면 바로 객체 a가 변경된다.
#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();
	friend Power& operator++(Power& op); // 전위 ++ 연산자 함수 프렌드 선언
	friend Power operator++(Power& op, int x); // 후위 ++ 연산자 함수 프렌드 선언
};

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

Power& operator++(Power& op) { // 전위 ++ 연산자 함수 구현
	op.kick++;
	op.punch++;
	return op; // 연산 결과 리턴
}

Power operator++(Power& op, int x) { // 후위 ++ 연산자 함수 구현
	Power tmp = op; // 변경하기 전의 op 상태 저장
	op.kick++;
	op.punch++;
	return tmp; // 변경이전의 op 리턴
}

int main() {
	Power a(3,5), b;
	b = ++a; // 전위 ++ 연산자
	a.show(); 	b.show();

	b = a++; // 후위 ++ 연산자
	a.show(); 	b.show();
}

 

TIP!! 연산자 함수는 멤버 함수나 프렌드 함수 중 어떤 것이 바람직한가?

  • 가능하면 클래스의 멤버 함수로 작성하기를 권한다.
  • 새로운 연산자는 클래스와 연계하여 작동하기 때문에!
  • 멤버로 선언하면 외부의 연산자 함수를 friend로 취할 필요도 없고 가독성도 높아지기 때문이다.
  • 또한 연산자 함수는 디폴트 매개 변수를 가질 수 없다..!

실습 : 참조를 리턴하는 << 연산자 작성해보기

#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 n); // 연산 후 Power 객체의 참조 리턴
};

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

Power& Power::operator <<(int n) {
	kick += n;
	punch += n;
	return *this; // 이 객체의 참조 리턴
}

int main() {
	Power a(1, 2);
	a << 3 << 5 << 6; // 객체 a에 3,5,6이순서대로 더해진다.
	a.show();
}
728x90

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

[C++] 상속과 객체 포인터  (0) 2023.12.14
[C++] 상속  (1) 2023.12.06
[C++] 연산자 중복  (0) 2023.12.06
[C++] 프렌드  (1) 2023.12.05
[C++] static 멤버  (0) 2023.12.05