연산자 오버로드(operator overload)//ostream 나중에 채워넣기

2020. 9. 10. 17:38컴퓨터 수업/C++

@연산자 오버로드

클래스 변수(객체)를 이용하여 프로그램을 작성하다 보면 클래스 변수끼리 덧셈,뺄셈,곱셈 등의 연산이 수행되도록 해야 하는 경우가 발생한다. 그러나 일반 연산자를 사용하여 객체끼리 덧셈이나 뺄셈을 수행할수는 없다.

C++에서는 기존의 연산자의 의미를 사용자가 임의로 변경하여 사용할 수 있도록 하는 연산자 오버로드(operator overload) 기능을 제공한다.

물론 +를 -로 기능하도록 바꾸고, *을 /로 바꾸는 그런 장난스러운 짓도 할 수 있겠지만, 본래 의미는 C++에서 기본적으로 제공하는 연산자의 기능을 특정 객체에 대해 동작하도록 사용자가 새로운 기능의 의미로 재정의 하는 것을 말한다. 따라서, 연산자를 오버로드해도 연산자가 가지고 있는 본래의 기능(의미)는 상실되지 않도록 해야한다.

 

@연산자 "오버로드"

지난 포스트에서 오버로드가 c++의 다형성을 지원하는 기능이라 하였다. +가 기본적인 자료형에 대해서 더하는 것이 아니라, 객체 끼리 더할 수 있게 된다는것이 왜 오버로드이고, 왜 다형성을 지원하는 것인가?

 

+에 새로운 자료형datatype  을 사용할 수 있게된다. (그것이 바로 객체composite data type) --> 오버로드

서로 다른 datatype에 대해서 특정 연산자를 이해할 수 있게된다 --> 다형성

 

@연산자 오버로드"하는법"

연산자를 오버로드하려면 연산자 함수를 정의하여야 한다.

-> 새로운 format을 만들어야 한다는 뜻

연산자 함수는 operator라는 예약어keyword를 갖는 함수로 이때, 연산자 함수는 클래스의 멤버 함수(멤버 연산자 함수)이거나 프렌드 함수(프렌드 연산자 함수)로 정의된다.

->operator라는 keyword가 붙는 새로운 함수를 만들건데, 이 함수는 멤버함수 이거나 외부+프렌드 함수로 클래스 내부의 데이터 멤버에 접근 할 수 있어야 된다는 뜻.

연산자 함수를 클래스의 멤버 함수나 프렌드 함수로 정의하는 방법은 일반 함수를 클래스의 멤버 함수나 프렌드 함수로 정의하는 방법과 동일하다.

 

이때, 그 새로운 format은 (클래스의 스코프나 프렌드를 제외하면) 다음과 같다.

datatype operator# ( argument )
{
...
}

이때 datatype은 대부분 객체의 클래스형이 될것이다. (객체끼리의 연산을 위해서 연산자 오버로딩 하는 경우가 대부분이라 했으니) 따라서 다음과 같다.

classname operator#(argument)
{
...
}

그리고 이때 #의 위치에는 오버로드할 연산자를 기술한다.

 

@이항 연산자의 오버로드

연산자 함수로 이항 연산자를 오버로드할 때는 연산자 함수 classname operator#(argument) 의 아규먼트는 단 하나이다.

(이항 연산자니까! -> 즉 특정 연산자에 대해서 연산할 대상(target = argument)가 단 하나이기 때문이다, 

즉 class1 + class2 의 경우 <class1+>(class2) 로써 this 포인터는 class1+ 함수에 전달된다.

 

이때, 연산자의 우측에 놓인 객체가 멤버 연산자 함수의 가인수에 전달되며/ 연산자의 좌측에 놓인 객체(scope)가 멤버 연산자 함수를 호출하게 된다. (멤버 연산자 오버로드와 프렌드함수를 이용한 오버로드를 하나의 예시에 대해 2번 작성하겠다.) 

 

+scope의 의미 : 해당 멤버 함수에 this 포인터를 전달한다.

 

@메소드를 이용한 이항 연산자의 오버로드 코드

#include <iostream>
using namespace std;
class vector
{
private:
	int x, y;
public:
	vector(int i = 3, int y = 2);
	vector operator+(vector);
	friend void get_data(vector);
};
vector::vector(int i, int j)
{
	this->x = i, this->y = j;
}
vector vector::operator+(vector b) // instance class::operator+(target instance)를 알아둘것
{
	b.x = this->x + b.x; // 어차피 복사생성된것이니
	b.y = this->y + b.y;

	return b;
}
void get_data(vector i)
{
	cout << "[" << i.x << " , " << i.y << "]" << endl;
}
int main()
{
	vector a, b(1, 1), c;
	c = a + b;

	get_data(c);
}

@프렌드함수를 이용한 이항 연산자 코드

#include <iostream>
using namespace std;
class vector
{
private:
	int x, y;
public:
	vector(int i = 3, int y = 2);
	friend vector operator+(vector a, vector b);
	friend void get_data(vector i);
};
vector::vector(int i, int j)
{
	this->x = i, this->y = j;
}
vector operator+(vector a, vector b)
{
	b.x = a.x + b.x;  // 어차피 복사 된거니까~
	b.y = a.y + b.y;
	
	return b;
}
void get_data(vector i)
{
	cout << "[" << i.x << " , " << i.y << "]" << endl;
}
int main()
{
	vector a, b(1, 1), c;
	c = a + b;

	get_data(c);
}

 

@메소드와 프렌드의 차이 <>를 function이라 하면 // 중요해!

<class+>(argument(target class)>와

(argument(target class1) <+> (argument(target class2) 의 차이이다. 

 

@실습 문제

3차원의 두 벡터 a와 b가 주어졌을 때, 두 벡터를 내적 및 더하는 프로그램을 작성하시오.

*연산자 오버로딩을 이용해서 아래에 주어진 메인 함수가 출력 예제와 동일하게 동작하도록 VecType Class를 구현하시오.

*클래스 생성자로 3개의 정수형 파라미터 입력을 받아 VecType 인스턴스가 초기화될 수 있도록 하시오.

#include <iostream>
#include "VecType.h"

using namespace std;

int main()
{
	VecType a(2, 5, 8);
	VecType b(3, 4, 7);
	int ip;

	ip = a.inner(b);
	cout << ip << endl;

	VecType c = a + b;
	cout << c << endl;

	return 0;
}

VecType.h

#pragma once
using namespace std;
class VecType
{
private:
	int vector[3];
public:
	VecType(int i = 1, int j = 2, int k = 3);
	int inner(VecType b);
	VecType operator+(VecType);
	friend ostream& operator<<(ostream& os , VecType b);
};
VecType::VecType(int i, int j, int k)
{
	vector[0] = i, vector[1] = j, vector[2] = k;
}
int VecType::inner(VecType b)
{
	int temp = 0;
	for (int i = 0; i < 3;i++)
	{
		temp += (this->vector[i] * b.vector[i]);
	}

	return temp;
}
VecType VecType::operator+(VecType b)
{
	b.vector[0] = b.vector[0] + this->vector[0];
	b.vector[1] = b.vector[1] + this->vector[1];
	b.vector[2] = b.vector[2] + this->vector[2];

	return b;
}
ostream& operator<<(ostream& os,VecType b)
{
	os << "[" << b.vector[0] << " , " << b.vector[1] << " , " << b.vector[2] << "]" << endl;
	return os;
}

 

언젠가 ostream도 이해할 날이 오겠징

VecType b말고 cosnt VecType &b를 애용하자. 복사생성자때매...

 

 

 

 

'컴퓨터 수업 > C++' 카테고리의 다른 글

파일 입출력(fstream)  (0) 2020.09.14
const에 관한 얘기  (0) 2020.09.13
friend 함수  (0) 2020.09.10
오버로딩과 다형성 (오버로딩은 그냥 다른 datatype 지원 그 자체다.)  (0) 2020.09.10
this 포인터  (0) 2020.09.10