관리 메뉴

공부 기록장 💻

[C++] 연산자 중복 함수 (Operator Overloading Function) 와 프렌드 함수 (Friend Function) 본문

# Language & Tools/C++

[C++] 연산자 중복 함수 (Operator Overloading Function) 와 프렌드 함수 (Friend Function)

dream_for 2021. 5. 5. 17:02

(명품 C++ 프로그래밍 7장)

 

 

프렌드 함수 (Friend Function)

 

 

friend 키워드 : 클래스 외부에 작성된 함수를 클래스 내에 선언하여, 클래스의 멤버함수와 동일한 접근 자격을 부여할 수 있도록 하는 키워드

 

friend 함수 : 클래스 내에 friend 키워드로 선언된 외부의 함수

- 멤버 함수는 아니므로, 상속되지는 않음

- 클래스의 멤버인 것처럼 클래스의 모든 변수나 함수에 접근 가능

- 프렌드 함수 개수에는 제한이 없음

 

 

프렌드 함수가 왜 사용될까?

- 클래스의 멤버 함수로는 적합하지 안지만, 클래스의 private, protected 멤버를 접근해야 하는 특별한 경우

- 연산자 함수에서 대표적으로 사용됨

 

프렌드 함수를 선언하는 경우 3가지

1. 클래스 외부에 작성된 함수를 프렌드로 선언 - friend 키워드 사용

2. 다른 클래스의 멤버 함수를 프렌드로 선언 - friend 키워드와 함께 클래스 이름과 범위 지정 연산자 :: 이용

3, 다른 클래스의 모든 멤버 함수를 프렌드로 선언 - friend 키워드와 클래스 이름 (해당 클래스의 모든 멤버를 자유롭게 접근가능)

 

 


프렌드 함수의 선언

 

- friend 키워드로 클래스의 아무 곳에서나 선언하면 됨

 

 

 

1. 외부에 선언된 전역 함수를 프렌드 함수로 선언

 

 

다음은 Rect 클래스에서 friend 키워드를 사용하여 외부에 선언된 equals 함수를 클래스 내부에서 선언한 예이다.

equals 함수는 두 Rect 객체의 width 와 height 를 각각 비교한 후, 두 객체가 동일한지 판별하는 함수이다.

클래스 멤버 함수로는 적합하지는 않으나, 클래스의 priavte 멤버로 선언된 width, height 변수에 접근해야 하므로 bools 함수를 friend 키워드를 이용하여 프렌드 함수로 선언하였다.

 

#include <iostream>
using namespace std;

class Rect; 			// 전방 선언(forward declaration)
bool equals(Rect r, Rect s); // 전방 참조(forward reference)

class Rect {
	int width, height;
public:
	Rect(int width, int height) {this->width = width; this->height = height;}
	friend bool equals(Rect r, Rect s); // euqlas 함수를 friend 함수로 선언
};

bool equals(Rect r, Rect s) {
	if (r.width == s.width && r.height == s.height) return true; // 객체의 private 멤버에 접근
	else return false;
}

int main() {
	Rect a(3, 4);
	Rect b(3, 5);
	if (equals(a, b))cout << "equal" << endl;
	else cout << "not equal" << endl;
}

 

Rect 클래스의 객체 a와 b는 height가 다르므로, 결국 not equal이 출력된다.

 

 

 

 

전방 참조(Forward Reference), 전방 선언(Forward Declaration)

 

위의 예제에서, Rect 클래스에서는 뒤에서 선언된 equals 함수를 friend 함수로 선언한다.

전방 참조를 하게 되는 경우이므로, Rect 클래스 이전에 equals 함수에 대한 선언이 필요하다.

이 떄, equals는 Rect 객체를 매개 변수로 전달 받는 함수이므로 뒤에 선언된 Rect 클래스에 대한 전방 참조를 한 것과 같다.

따라서 이에 대해서도 Rect 클래스에 대한 선언이 이전에 이루어져야 한다.

 

 

정리하면, 뒤에서 선언되는 이름을 미리 사용하게 되는 경우를 전방 참조(forward reference) 라 하고,

이를 해결하기 위해 전방 참조가 이루어지기에 앞서 클래스 혹은 함수에 대해 선언해주는 것을 전방 선언(forward declaration)이라고 한다.

 

class Rect; // 전방 선언(forward declaration)
bool equals(Rect r, Rect s); // 전방 참조(forward reference)

 


 

2. 다른 클래스의 멤버 함수를 프렌드로 선언

 

 

이번에는 equals 함수가 RectManager 클래스에 선언되어 있는 멤버 함수라고 가정하자.

다른 클래스에 있는 멤버 함수를 프렌드로 선언하면 다음과 같이

friend키워드와 :: 범위 지정 연산자, 그리고 함수를 적어주면, Rect클래스의 모든 멤버를 접근할 수 있게 된다.

 

class Rect {
	...
   	 // RectManager 클래스에 선언되어 있는 euqlas 함수를 friend 함수로 선언
	friend RectManager::bool equals(Rect r, Rect s);
};

 

 

 

3. 다른 클래스의 전체 멤버 함수를 프렌드로 선언

 

이번에는 RectManager 클래스의 모든 멤버 함수를 프렌드 함수로 선언해보자.

RectManager 클래스를 Rect 클래스에 프렌드로 초대하려면,

다음과 같이 friend 키워드와 클래스 이름을 적어주면 된다.

 

class Rect {
	...
   	 // RectManager 클래스에 선언되어 있는 모든 멤버 함수를 friend 함수로 선언
	friend RectManager;
};

 


 

- 다형성(polymorphism): 동일한 연산/기호를 대상(피연산자(에 따라 서로 다른 의미로 해석하는 것

ex ) 함수 중복(function overloading)

 

 

연산자 중복(Operator Overloading)

- 피연산자에 따라 서로 다른 연산을 하도록 동일한 연산자를 중복해서 작성하는 것

 

 

< '+' 덧셈 연산자의 활용 예 - 다형성의 예시 >

 

1) 두 정수에 대한 덧셈 연산 ( 2+3=5 )

2) 두 문자열(string 객체) 합치기 ( "Hello ", "C++Programming"="Hello C++Programming" )

3) 두 색을 섞은 새로운 색 만들기 ( Red + Blue = Purple )

4) 두 배열 더하기 ( {1,2,3} + {4,5,6} = {1,2,3,4,5,6} )

 

 

<연산자 중복의 특징>

 

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

- +, -, *, /, ==, !=, %, &&, ||, <<, <=, new[] 등

 

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

- 객체+수, 수+객체, 객체+객체

 

3. 연산자 함수(operator function): 새로운 연산 처리를 수행하는 함수를 구현

 

4. 클래스와의 관계를 가진다. 피연산자에 객체를 동반한다.

- 클래스의 멤버 함수로 구현

- 전여 함수로 구현하고 클래스에 프렌드 함수로 선언

 

5. 피연산자의 개수를 바꾸는 것은 불가능

 

6. 연산자의 우선순위 변경 불가능

 

7. 중복이 불가능한 연산자: '.', '.*', '::'(범위 지정 연산자), ? : (3항 연산자) 

 

 


연산자 함수

 

연산자 중복은 연산자 함수를 통해 구현된다. 연산자 함수의 작성 방법은 2가지가 있다.

 

1. 클래스의 멤버 함수로 구현 (자신 객체에 대한 포인터 this, 같은 클래스의 다른 객체 이용)

2. 외부 함수로 구현, 클래스의 프렌드 함수로 선언 (두 객체 이용)

 

 

 

연산자 함수 선언

 

연산자 함수는 operator 키워드를 이용해 선언한다.

기존의 함수 선언과 더불어 'operator' 키워드와 '연산자'가 추가된다. 

 

 

다음은 두 Color 객체를 더하고 두 객체가 동일한지 확인하는 +, == 연산자에 대한 연산자 함수를

외부 함수로 구현하고 클래스에 프렌드 함수로 선언한 첫번째 방법,

멤버 함수로 선언한 두번째 방법을 나타낸 코드이다.

 

리턴타입 operator 연산자(매개변수리스트);

// 두 Color 객체를 더하는 연산자 함수

// 1. 외부 함수로 구현하고 클래스에 프렌드로 선언
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);
};


// 2. 클래스의 멤버 함수로 선언
class Color{
	...
    Color operator + (Color op2); // 왼쪽 피연산자는 객체 자신, 오른쪽 피연산자가 op2에 전달
    bool operator == (Color op2); 
};

 

 

 

 

 


 

 

이제부터 연산자 중복의 예제로 사용할 클래스는 Power 클래스이다.

게임에서 발로 차는 kick, 그리고 주먹으로 때리는 힘 punch 두 멤버 변수를 가진 클래스이다.

 

class Power{
	int kick;
	int punch;
public:
	Power(int kick=0, int punch=0){
		this->kick=kick;
		this->punch=punch;
	}
};

 

 


이항 연산자 중복

이항 연산자(binary operator)는 2개의 피연산자를 갖는 연산자이다.

+, -, ==, += 산술 중복 이항 연산자를 이용해 두 객체(피연산자)를 연산하는 과정을 살펴보자.

 

 

 

+ 연산자 중복

두 Power 객체를 더하는 + 연산자를 이용하여 두 멤버 변수인 kick과 punch 를 더하도록 할 것이다.

 

// 3개의 객체(2개의 피연산 객체, 결과값 저장할 1개의 객체)

Power a(3,5), b(4,6), c;
c = a + b;

 

 

Power 클래스의 멤버 함수로 + 이항 연산 함수를 선언하면 a + b 를 실행하면, 컴파일러는 다음과 같이 처리한다.

왼쪽 피연산자인 a 객체의 멤버함수 operator +() 를 호출하여, 

b를 매개 변수로 넘겨주는 함수 호출이다.

 

a. + ( b ); // a 객체의 멤버함수 operator + 호출하여 매개 변수 객체인 b와 연산을 실행

 

 

멤버 함수로 operator + () 를 구현하면 다음과 같다.

this 는 Power 객체 a 자신에 대한 포인터이고, op2는 Power 객체 b를 전달받은 매개 변수이다.

연산의 결과를 저장하기 위해 선언한 tmp 객체가 반환되며, Power c의 객체에 반환 객체가 저장된다.

 

class Power{
	...
    
	Power operator + (Power op2){ // 참조 매개 변수를 사용해도 무관하다. (Power &op2) 객체의 복사가 이루어지지 않아 효과적
		Power tmp;
		tmp.kick = this->kick + op2.kick;
		tmp.punch = this->punch + op2.punch;
		return tmp;
	}
};

 

 

 

+ 연산자 중복 2

 

이번에는 동일한 두 Power 객체를 더하는 것이 아닌,

한 개의 Power 객체와 정수(객체)를 더하는 + 연산자 중복을 구현해보자.

kick 값과 punch 값과 정수를 각각 더하는 연산이다.

 

Power 객체 a와 b에 대하여, b = a + 2; 를 계산하기 위해 구현하면 다음과 같다.

 

class Power{
	...
    
	Power operator + (int op2){
		Power tmp;				// 반환할 tmp 객체 선언
		tmp.kick = kick + op2;	// a의 kick 에 정수 op2를 더함
		tmp.punch = punch + op2; // a의 punch 에 정수 op2를 더함
		return tmp;
	}
    ... // get 함수포함
};

int main(){
	Power a(1,2), b;
	b=a+2; // c는 a에 '2'라는 객체를 더한 객체
	
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;	
}

 

결과창을 보면, a의 kick과 punch 값에 각각

2를 더한 값을 객체 b가 가지고 있음을 확인할 수 있다.

 

 

 

 


== 연산자 중복

두 객체가 같은지 확인하는 operator==() 함수를 구현해보도록 할 것이다.

 

위의 + 연산자와 동일하게,

Power 객체 a의 멤버 함수로 operator==() 함수를 호출하면, 다음과 같이 컴파일러가 b를 매개 변수로 넘겨 연산 함수를 처리한다.

 

a . == ( b )

 

 

operator==() 연산자 멤버 함수를 구현해보면 다음과 같다.

두 객체를 비교하는 연산 함수이므로, 반환 값은 boolean 형이다.

a 객체 자신에 대한 포인터 this를 이용해, a의 kick값과 punch 값이 

매개 변수로 받은 op2 객체의 kick 값과 punch 값과 각각 동일하면 true값을, 아니라면 false값을 리턴하게 된다.

 

class Power{
	...
    
	bool operator== (Power op2){
		return (this->kick==op2.kick && this->punch==op2.punch);
	}
};

 

 


+= 연산자 중복

+= 연산은 a와 b를 합쳐 a를 새로운 Power 객체로 갱신하는 것으로 정의한다.

따라서 '참조'를 사용해야 한다!

 

다음과 같이, a의 멤버 함수인 operator +=() 연산 함수가 실행되면,

a의 객체의 멤버 변수인 punch 와 kick 값에 b의 punch와 kick 값이 각각 더하여 갱신이 된다.

그리고 객체 a의 참조를 리턴하게 되면, 객체 b 가 객체 a에 더해져 갱신되어 객체 a 가 반환된다.

 

a += b;

// 컴파일러의 처리
a . += ( b ); // a의 객체에 매개변수로 전달된 b 객체를 더하여 갱신

 

 

구현하면 다음과 같다.

 

class Power{
	...
    
	Power& operator += (Power op2){
		kick = kick + op2.kick; // 객체 a의 kick 값에 op2의 kick 값을 더하여 갱신
		punch = punch + op2.punch; // 객체 a의 punch 값에 op2의 punch 값을 더하여 갱신
		return *this;
	}
};

 

 

 

Power 클래스의 멤버 함수인 operator +=() 중복 연산자 함수가 포함된

다음 프로그램을 실행해보고 결과값을 확인해보자.

 

#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;
	}
	Power& operator += (Power op2){
		kick += op2.kick; 
		punch += op2.punch; 
		return *this;
	}
	int getKick(){return this->kick;}
	int getPunch(){return this->punch;}
};

int main(){
	Power a(1,2), b(2,3), c;
	c=a+=b; // c는 a에 b를 더한 객체
	
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;
	cout<<"객체 c : "<<c.getKick()<<" "<<c.getPunch()<<endl;
}

 

 

다음의 결과창을 통해 객체 a의 멤버 변수 값이 (1, 2) 에서 (1+2==3, 2+3==5) 로 갱신되었고,

그 값이 c에 저장된 것을 확인할 수 있다.

 


단항 연산자 중복

 

단항 연산자(unary operator) 는 연산자의 위치에 따라 다음과 같이 나눌 수 있다.

 

 

- 전위 연산자(prefix operator)

  • !op, ~op, ++o, --op
  • b=++a (객체 a에 대한 전위 연산을 실행하여 갱신 후, 그 결과를 b에 저장)
  •  

- 후위 연산자(postfix operator)

  • op++, op--
  • b=a++ (객체 b는 우선 a를 저장하고, 이후 객체 a에 대한 후위연산을 실행하여 갱신)

 

 


 

전위 ++ 연산자 중복

 

하나의 객체에 대한 전위 연산을 실행 후, 다른 객체에 대입을 하는 전위 ++ 연산자 중복이다.

 

다음은 a 객체에 대한 전위 연산을 실행하고, 변경된 a를 b에 대입하게 되는 경우이다. 

a의 kick, punch 값이 각각 1씩 증가하여 변경된 객체 a를 b에 저장하게 된다.

 

Power a(1,2), b;
b = ++a; // ++a = b; 참조리턴 r-,l- value 모두 가능

 

 

이를 구현하면 다음과 같다.

a의 kick, punch 값이 각각 1씩 증가한 후, 변경된 객체 자신(객체 a)를 참조 리턴하게 된다.

 

class Power{
	...
    
	Power& operator ++ (){
		kick++; // a의 kick값 1 증가 
		punch++; // a의 puch값 1 증가 
		return *this;	// 변경된 객체 자신(객체 a)을 참조 리턴 
	}
    ...
};

 

실행 결과를 보면 다음과 같다.

(0, 0)으로 초기화 되어 있던 객체 b에 전위 연산을 실행한 객체 a가 대입되어

kick, punch 값이 동일한 객체가 되었음을 확인할 수 있다.

 

 

 


후위 ++ 연산자 중복

 

클래스의 멤버함수로서의 후위 ++ 연산자 함수는 전위 연산자 함수와 구분하기 위해,

다음과 같이 의미 없는 매개 변수를 가지도록 선언된다. (매개 변수 x에는 의미 없는 값이 전달되므로 무시하면 된다.)

 

Power operator ++ (); // 전위 ++ 연산
Power operator ++ (int x); // 후위 ++ 연산

 

 

b = a++; 를 실행한다고 하면,

b에 먼저 객체 a를 대입한 후에, a의 kick 과 punch 값에 대한 증가가 일어나게 되는 연산이다.

 

b = a++;

// 컴파일이 처리하는 것은 다음과 같다.
b = a. ++ (임의의 정수)

 

 

후위 ++ 연산자 함수는 다음과 같이 구현할 수 있다.

임시 객체를 먼저 선언하여, 현재 a값을 저장하고

이후에 a의 punch와 kick 값을 증가시키도록 한다.

증가 이전의 a를 저장한 tmp 객체를 마지막에 반환하게 된다.

 

	Power operator ++ (int x){
		Power tmp = *this; // 증가 이전 객체를 tmp에 저장 
		kick++;
		punch++;
		return tmp;	// 후위 증가가 일어난 후, 증가 이전에 저장했던 tmp를 반환	
	}

 

 

다음과 같이 객체 a의 후위 연산을 실행하여 b에 대입하도록 함수를 호출해보자

 

int main(){
	Power a(1,2), b;
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;
	
	b = a++; // a에 대한 전위연산 후 b에 대입(증가한 a를 b에 저장) 
	
	cout<<endl<<"후위 연산 이후"<<endl; 
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;	
}

 

아래와 같이, 객체 b는 증가 이전의 a가 대입되었음을,

객체 a는 kick 과 punch 값이 각각 1 증가한 값으로 변경되었음을 확인할 수 있다.

 

 

 


! 연산자 함수

 

객체의 kick과 punch 값이 모두 0인 경우 true를 반환하는 operator !() 연산자 중복 멤버 함수는 다음과 같다.

 

bool operator !(){ return (kick==0 && punch==0);}

 

 

main 함수에서는 다음과 같이 ! 중복 연산 함수를 사용할 수 있다.

int main(){
	Power a(0,0), b(0,1);
	
	if(!a) cout<<"a의 파워가 0이다."<<endl;
	else cout<<"a의 파워가 0이 아니다."<<endl;
	if(!b) cout<<"b의 파워가 0이다."<<endl;
	else cout<<"b의 파워가 0이 아니다."<<endl;
}

 

 

 

Power 클래스에 선언된 다양한 이항 연산자

(왼쪽 피연산자 - 객체 A, 오른쪽 피연산자 - 객체 B, 정수 3)

 

연산자 사례 컴파일러에 의해 변형된 호출식 클래스의 연산자 멤버 함수
+ a+b a.+(b) Power operator + (Power& op2)
!= a!=b a.!=(b) bool operator != (Power& op2)
+= a+=b a.+=(b) Power& operator += (Power& op2)
+ a+3 a.+(3) Power operator += (int op2)
> a>3 a.>(3) bool operator (int op2)
+= a+=3 a.+=(3) Power& operator += (int op2)

 

Power 클래스에 선언된 다양한 이항 연산자

(왼쪽 피연산자 - 객체 A)

연산자 사례 컴파일러에 의해 변형된 호출식 클래스의 연산자 멤버 함수
! !a a.!() bool operator ! ()
~ ~a a.~() Power operator ~ ()
전위 ++ ++a a.++() Power& operator ++ ()
후위 ++ a++ a.++(0) Power operator ++ (int x)
전위 -- --a a.--() Power& operator -- ()
후위 -- a-- a.--(0) Power& operator -- (int x)

 

 

 


 

프렌드 이용한 연산자 중복

 

연산자 함수는, 외부 전역 함수로도 작성이가능하다.

해당 외부 연산자 함수를 friend로 취하여 클래스의 멤버를 자유롭게 접근할 수 있게 한다. 

 

 

우선, 클래스 내부의 함수로 사용하기 어려운 경우는 다음과 같다.

 

 

왼쪽 피연산자가 객체가 아닌 경우 : b = 2 + a;

 

다음과 같이, b = a + 2; 처럼 클래스 내부의 operator + () 연산자 멤버 함수를 사용할 수 없는 경우가 있다.

객체가 아닌 정수 2가 왼쪽 피연산자가 되는 경우이다.

a.+(2) 와 같이, 2.+(a) 를 사용할 수 없다. 2는 Power 클래스의 객체가 아니기 때문이다.

 

 

Power a(1,2), b;
b = 2 + a; // 왼쪽 피연산자가 2이다.

 

이러한 경우, Power 클래스의 외부 함수로 밖에 구현할 수 없다.

operator + () 연산자 함수를 외부에 구현한 것은 다음과 같다.

 

class Power{
	int kick;
	int punch;
public:
	...
    
	// friend 키워드를 이용해 외부의 + 연산자 함수를 초데 
	friend Power operator + (int op1, Power op2);
};

// + 연산자 함수 외부에 구현 
Power operator + (int op1, Power op2){
	Power tmp;
	tmp.kick = op1 + op2.kick; // op2의 멤버 변수 kick에 접근 
	tmp.punch = op1 + op2.punch; // op2의 멤버 변수 punch에 접근 
	return tmp;
}

 

정수 op1과 객체 op2를 매개변수로 전달 받아, 임시 객체 tmp에 두 값을 더한 값을 저장한다.

이 때, op2 객체의 private 멤버 변수인 kick과 punch에 접근하기 위해서는,

해당 외부 함수를 Power 클래스 내부에 friend로 선언하여야 한다.

 

 

 

 

 

punch와 kick 멤버 변수를 publich 으로 선언하여 멤버 함수로 이를 작성할 수 있지 않은가?

=> 아니다! 이는 클래스의 캡슐화 원칙을 무너뜨리게 되는 치명적인 판단 미스이다.

따라서 friend를 사용하여 해결하는 것이 옳다 !

 

 

 

 


두 객체를 더하는 외부 + 연산자 함수를 프렌드로 작성

 

class Power{
	int kick;
	int punch;
public:
	...
    
	friend Power operator + (Power op1, Power op2);
};

Power operator + (Power op1, Power op2){
	Power tmp;
	tmp.kick=op1.kick+op2.kick;
	tmp.punch=op1.punch+op2.punch;
	return tmp;
}

 

 


단항 ++ 연산자 함수를 프렌드로 작성

 

전위, 후위 ++ 연산자 함수를 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;
	}
	int getKick(){return this->kick;}
	int getPunch(){return this->punch;}
		
	friend Power& operator ++ (Power &op);
	friend Power operator ++ (Power& op, int x);
};

// 전위 ++ 연산자 함수 
Power& operator ++ (Power& op){
	op.kick++;
	op.punch++;
	return op;
}

// 후위 ++ 연산자 함수 
Power operator ++ (Power& op, int x){
	Power tmp = op; // 증가 이전의 객체 대입 
	op.kick++; // 참조된 op의 kick, punch 값 증가 
	op.punch++; 
	return tmp;
}
int main(){
	Power a(1,2), b, c(1,2), d;
	
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;
	cout<<"객체 c : "<<c.getKick()<<" "<<c.getPunch()<<endl;
	cout<<"객체 d : "<<d.getKick()<<" "<<d.getPunch()<<endl;
	
	b=++a;
	d=c++;
	
	cout<<endl<<"전위, 후위 ++ 연산 이후"<<endl; 
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b(++a) : "<<b.getKick()<<" "<<b.getPunch()<<endl;
	cout<<"객체 c : "<<c.getKick()<<" "<<c.getPunch()<<endl;
	cout<<"객체 d(c++) : "<<d.getKick()<<" "<<d.getPunch()<<endl;
}


참조를 리턴하는 << 연산자 

 

정수 값 입력

 

<< 연산자를 중복하여 멤버 함수로 작성해보자.

정수의 값이 나오면, kick과 punch 값에 각각 해당 정수를 더하여, 객체를 갱신하는 것이다.

 

다음 예제는 << 연산을 두 번 사용하여, 3과 10을 입력하여 객체 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;
	}
	int getKick(){return this->kick;}
	int getPunch(){return this->punch;}
		
	// < 연산자 중복 멤버 함수 
	Power& operator << (int op){
		kick+=op;
		punch+=op;
		return *this;
	}
};


int main(){
	Power a(0,1);
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	
	a<<3<<10; // a의 kick과 punch에 각각 3을 더하고, 10을 더한다.
	 
	cout<<endl<<"<< 연산 후"<<endl;
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
}

 

3과 10, 총 13이 더해져 punch와 kick값이 다음과 같이 변경된 것을 확인할 수 있다.

 

 

 

 

 


 

객체 입력

 

이번엔 정수값을 더하는 것이 아닌, 객체를 입력하여 punch와 kick 값을 각각 더하여 갱신하도록 해보자

 

다음과 같이 매개변수를 정수가 아닌, 객체로 변경하고

구현에서는 멤버 변수에 접근하여 kick과 punch값을 더하여 갱신하도록 하면 된다.

 

	Power& operator << (Power op2){
		kick+=op2.kick;
		punch+=op2.punch;
		return *this;
	}

 

main 함수가 다음과 같을 때,

 

int main(){
	Power a(0,1), b(3,3), c(2,4);
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
	cout<<"객체 b : "<<b.getKick()<<" "<<b.getPunch()<<endl;
	cout<<"객체 c : "<<c.getKick()<<" "<<c.getPunch()<<endl;
	
	a<<b<<c; // a의 kick과 punch에 각각 3을 더하고, 10을 더한다.
	 
	cout<<endl<<"a<<b<<c 연산 후"<<endl;
	cout<<"객체 a : "<<a.getKick()<<" "<<a.getPunch()<<endl;
}

 

객체 a에 b와 c를 연속으로 입력하고,

변경된 a값을 확인해보면 다음과 같다.

 

 

 

원본(*this) 에 대한 참조(&)를 리턴하게 되는 << 중복 연산자 멤버 함수에 대해서 알아보았다.

 

 

 

728x90
반응형
Comments