본문 바로가기
KNOU/C++

[C++ 프로그래밍]연산자 다중정의

by bottlesun 2022. 12. 1.
728x90

피연산자의 자료형과 연산자

  • 동일한 연산자라도 구체적인 처리 방법은 피연산자의 자료형에 따라 달라진다.

연산자 다중정의란?

  • c++ 에 정의된 연산자를 사용자가 선언한 클래스의 객체에 대하여 사용 할 수 있도록 정의 하는 것
  • 연산자의 의미를 임의로 바꾸지 않는다.
  • 고유의 특성이 유지되도록 한다.

연산자의 다중정의 위치

  • 클래스의 멤버로 정의하는 방법
  • → 연산자의 구현 과정에서 객체의 멤버를 액세스 할 수 있음
  • 클래스 외부에서 정의하는 방법
  • → 클래스의 멤버가 아니므로, 객체의 private 멤버는 직접 사용 x

다중정의 형식

전위 표기법

ReturnClass ClassName::operator opSymbol()
{
······
}

opSymbol : ++ , — 등의 단항 연산자 기호

형식 매개변수 x

후위 표기법

ReturnClass ClassName::operator opSymbol(int)
{
······
}

형식 매개변수 표기는 인수 전달의 의미가 아닌 후위 표기법임을 나타냄

이항 연산자의 다중정의

ReturnClass ClassName::operator opSymbol(ArgClass arg)
{
······
}

opSymbol : +, -, *, /, &&, || 등의 이항 연산자 기호

객체 자신이 좌측 피연산자, arg가 우측 피연산자에 해당됨

복소수 객체와 복소수 객체의 덧셈 연산자

// 수식 : complex2Obj1 + complex2Obj2
Complex2 Complex2::operator + (const Complex2 &c) const
// complex2Obj1 = *this
// c = complex2Obj2
{
······
}

실수와 복소수의 객체의 덧셈 연산자

좌측 피연산자가 실수이므로 Complex2 클래스의 멤버로 연산자를 정의할 수 없음

// 수식 : 10.0 + complex2Obj
// error private 멤버 사용
Complex2 operator + (double r, const Complex2 &c)
{
return Complex2(r + c.rPart, c.iPart);
}

에러 해결 1

private 멤버를 엑세스 할 수 있는 멤버함수 정의

class Complex2 {
double rPart, iPart;
public:
······
double real() const { return rPart; } // 실수부의 값 반환
double imag() const { return iPart; } // 허수부의 값 반환
};

Complex2 operator + (double r, const Complex2 &c)
{
return Complex2(r + c.real(), c.imag());
}

에러 해결2

다중 정의 된 연산자를 friend 로 선언

class Complex2 {
double rPart, iPart;
public:
······
friend Complex2 operator + (double r, const Complex2& c);
};

Complex2 operator + (double r, const Complex2 &c)
{
return Complex2(r + c.rPart, c.iPart);
}

대입연산자 (=)

  • 묵시적 대입 연산자 : 우측 피연산자 데이터 멤버를 좌측 피연산자에 그대로 복사함
  • 객체에 동시 할당된 메모리를 가리키는 포인터가 포함되어 있을 경우 얕은 복사가 된다. (공유 상태 문제 발생)

→ 깊은 복사 필요

// VecF :: operator -> a  = fv -> b / a = b 
VecF& VecF :: operator = (const VecF& fv){
	if (n != fv.n) { // 백터가 n이 아니라면
		delete[] arr; // 기존 메모리 초기화
		arr = new float[n = fv.n]; // 메모리 할당
	}
	memcpy(arr, fv.arr, sizeof(float)*n); // 데이터 복사
		return *this;
}
	

이동대입연산자(=)

  • 좌측 피연산자에 대입 할 우측 피연산자가 rvalue 일 때 사용 됨
  • → 대입 후 우측 피연산자의 내용이 더이상 필요 없는 상황
VecF& VecF :: operator = (VecF&& fv){ // 우측피연산자는 값이 바뀔 수 있기에 const 안씀
	delete[] arr; // 기존 메모리 초기화
	n = fv.n;     // 우측 피연산자의 내용을 이동
	arr = fv.arr;	
	fv.arr = nullptr;
	return *this;
}

두 VecF 객체를 교환하는 함수의 구현

std::move 함수 사용

  • 인수로 전달되는 객체의 rvalue 참조를 반환
VecF tmp = std :: move(v1);

→ v1의 rvalue 참조를 구하여 tmp의 초기화에 사용

→ 이동 생성자를 이용하여 tmp 생성

v1 = std::move(v2);

→ v2 의 rvalue 참조를 구하여 v1에 대입

→ 이동 대입 연산자 실행

[ ] 연산자의 다중정의

[ ] 연산자

  • 배열의 첨자를 지정하는 이항 연산자
  • 피연산자 → 배열의 첨자

데이터를 저장하기 위해 사용할 [ ] 연산자

SafeIntArray a(10);
a[5] = 10;

int& SafeIntArray::operator[](int i){
// 좌측 피연산자 a = *this // 매개변수 i = [5]
......
}

const 객체를 위한 [ ] 연산자

  • 데이터를 읽기만 할 수 있도록 [ ] 연산자를 정의함
  • const 는 읽기 전용이기에, 그냥 첨자 연산자의 다중정의로는 error 가 나온다 const로 두번 지정해줘야함
void f(const SefeIntArray & x) {
	for(int i = 0; i < x.size(); i++)
	const << x[i] << endl;
}

int SafeIntArray::operator[](int i) const {
......
}
728x90

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

[C++프로그래밍] 예외처리  (0) 2022.12.01
[C++ 프로그래밍]템플릿  (0) 2022.12.01
[C++ 프로그래밍] 클래스와 객체  (0) 2022.12.01
[C++ 프로그래밍] 함수  (1) 2022.12.01

댓글