연산자 오버로딩

이영준·2022년 3월 31일
0
post-thumbnail

🔑연산자 오버로딩

• 프로그래머는 대부분의 빌트인 연산자를 재정의하거나 오버로드할 수 있습니다.
• 프로그래머는 사용자 정의 유형을 가진 연산자를 사용할 수도 있습니다.
• 오버로드된 연산자는 키워드인 operator 뒤에 정의되는 연산자의 기호가 이어지는 특별한 이름을 가진 함수입니다.
• 다른 함수와 마찬가지로 오버로드된 연산자에는 반환 유형과 파라미터 목록이 있습니다.

ex> Plus Operator
Unit Unit::Operator+(Unit right){}

연산자 오버로딩 규칙

• 연산자의 우선순위는 오버로드의 영향을 받지 않습니다.
• 오버로드된 연산자는 기본값 매개변수를 사용할 수 없습니다.
• 연산자 ::(범위 확인), . (멤버 액세스), .*(멤버 포인터를 통한 멤버 액세스) 및 ?:(기본 조건)은 오버로드할 수 없습니다.
• **, <>, 또는 &| 등의 새 연산자를 생성할 수 없습니다.
• 연산자 =, [], () 및 ->는 멤버 함수로만 정의할 수 있습니다.

이항 연산자(+,-, 등등)
• 첫 번째(왼쪽) 개체는 연산자 오버로드 함수 발신자이고 두 번째(오른쪽) 개체는 전달된 인수입니다.
• 왼쪽 개체(함수 호출자)는 this 포인터를 사용하여 액세스할 수 있습니다.

이항 연산자 오버로딩 퀴즈

ex1) - 연산자 오버로딩

#include <iostream>

using namespace std;

class Unit {
private: 
	int hp;

public:
	Unit() { hp = 0; }
	Unit(int i) { hp = i; }

	int GetHP() { return hp; }

	Unit operator-(Unit right);



};

Unit Unit::operator-(Unit right) {
	Unit temp;
	temp.hp = hp - right.hp;
	return temp;
}

int main() {
	Unit Unit1(10), Unit2(5), Unit3;
	Unit3 = Unit1 - Unit2;

	cout << "Unit1 hp : " << Unit1.GetHP() << endl;
	cout << "Unit2 hp : " << Unit2.GetHP() << endl;
	cout << "Unit3 hp : " << Unit3.GetHP() << endl;
}

연산자 오버로딩 함수에서 hp는 이항연산자의 좌측에 해당하는 unit의 hp, 이고 right.hp가 연산자의 우측에 있는 unit으로 매개변수로 쓰이는 것과 같이 실행된다.

ex2) 연산자 오버로딩 및 상속

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>


using namespace std;

class Unit {
private:
	int hp;
	int mp;
	int unitSize;
	char* name;
public:
	Unit() {
		hp = 0;
		mp = 0;
		unitSize = 0;
		name = NULL;
	}

	Unit(int hp, int mp, int unitSize, const char* argName) : hp(hp), mp(mp), unitSize(unitSize) {
		name = new char[strlen(argName) + 1];
		strcpy(name, argName);
	}

	~Unit() {
		if (!name) {
			delete[] name;
			name = NULL;
		}
	}

	int GetSize() { return unitSize;}

	int operator+(Unit right) { return unitSize + right.unitSize; }
	int operator-(Unit right) { return unitSize - right.unitSize; }
	int operator*(Unit right) { return unitSize * right.unitSize; }

};

class HUnit :public Unit {//자식클래스
public:
	HUnit(): Unit(45, 125, 2, "HUnit") {}
};

void funcUnit(Unit a) {
	cout << a.GetSize() << endl;
}

void funcHUnit(HUnit a) {
	cout << a.GetSize() << endl;
}
int main() {
	HUnit c1, c2;
	cout << "Total Unit Size (+): " << c1 + c2 << "\n";
	cout << "Total Unit Size (-): " << c1 - c2 << "\n";
	cout << "Total Unit Size (*): " << c1 * c2 << "\n";

	Unit a;
	funcUnit(a);
	//funcHUnit(a);

	HUnit b;
	funcUnit(b);
	funcHUnit(b);
}

위 구문에서 funcHUnit(a)는 실행되지 않는다, HUnit이 Unit에게서 상속받아 HUnit은 Unit형에 포함되나 Unit이 HUnit형에 포함되지는 않기 때문이다.

🔑비교, 논리연산자 오버로딩

• 오버로딩이 가능합니다.
• 모든 임베디드 연산자는 bool을 반환하고 대부분의 사용자 정의 오버로드도 bool을 반환하므로 사용자 정의 연산자는 임베디드 연산자와 동일한 방식으로 사용할 수 있습니다.
• 단, 사용자 정의 연산자 오버로딩에서는 모든 유형을 반환 유형(void 포함)으로 사용할 수 있습니다.

#include <iostream>

using namespace std;

class Unit {
private:
	int hp;

public:
	Unit() { hp = 0; }
	Unit(int i) { hp = i; }

	int GetHP() { return hp; }

	int operator!=(Unit right);

};

int Unit::operator!=(Unit right) {
	if (hp != right.hp) {
		return 1;
	}
	return 0;
}

int main() {
	Unit Unit1(10), Unit2(5), Unit3(5);

	if (Unit1 != Unit2)
		cout << "Unit1 != Unit2\n";
	else
		cout << "Unit1 == Unit2\n";

	if (Unit2 != Unit3)
		cout << "Unit2 != Unit3\n";
	else
		cout << "Unit2 == Unit3\n";

결과:
Unit1 != Unit2
Unit2 == Unit3

🔑단항 연산자 오버로딩

단항 연산자의 오버로딩
• 단항 연산자는 단일 피연산자에서 작동합니다.
  – 입력 인수 없음 (postfix=후위표기식 ex)a++ 제외)
• 단항 연산자의 반환 유형에는 제한이 없습니다. 예를 들어 논리 NOT(!)가 정수값을 반환하는 것이 타당합니다.
• 오버로드할 수 있는 단항 연산자:
  – ! (논리적 NOT), & (주소), ~ (보완), * (점수 삭제), + (단수 플러스), - (단수 부정), + + (증분), -- (감소), 변환 연산자

단항 연산자 오버로딩 예제

전위표기식 Unit1 = ++Unit3(1 더햊진 Unit3값을 Unit1에 넣기)와
후위표기식 Unit1 = Unit3++(Unit1에 Unit3값 넣고 Unit3을 ++)
는 표기법이 다르다

전위: Unit operator++()
후위: Unit operator++(int)


#include <iostream>

using namespace std;

class Unit {
private:
	int hp;

public:
	Unit() { hp = 0; }
	Unit(int i) { hp = i; }

	int GetHP() { return hp; }

	Unit operator++() {
		hp++;
		return *this;
		//Unit temp;
		//temp.hp = ++hp;
		//return temp;

	};

	Unit operator++(int) {
		Unit temp;
		temp.hp = hp++;
		return temp;
	}
};

int main() {
	Unit Unit1, Unit2, Unit3(10);


	Unit1 = Unit3++;
	Unit2 = ++Unit3;

	cout << Unit1.GetHP() << "\n";
	cout << Unit2.GetHP() << "\n";
}

결과:
10
12

🔑Friend 함수 이용한 오버로딩

• 연산자는 friend 함수로 정의할 수 있습니다.
• 단항 연산자에 대한 인수 하나와 이항 연산자에 대한 인수 두 개입니다.
• 할당 연산자 '='은(는) friend 함수가 아닌 멤버 함수를 사용하여 오버로드될 수 있습니다.

//이항
Unit operator+(Unit left, Unit right){
}
//단항
Unit operator++(Unit left){
]
//단항, 후위식
Unit operator++(Unit left, int){
}

일반적으로 함수 선언할 때와 달리 좌측항의 값을 받는 인수가 하나씩 더 붙음

#include <iostream>

using namespace std;

class Unit {
private:
	int hp;

public:
	Unit() { hp = 0; }
	Unit(int i) { hp = i; }

	int GetHP() { return hp; }

	friend Unit operator+(Unit left,Unit right);

};

Unit operator+(Unit left, Unit right) {
	return left.hp + right.hp;
}

int main() {
	Unit Unit1(10), Unit2(5), Unit3(5);

	Unit3 = Unit1 + Unit2;
	cout << "Unit3 : " << Unit3.GetHP() << endl;
}

Friend함수는 메서드 함수가 아니므로, this를 갖지 않는 만큼 left값도 받아와야 함!

🔑레퍼런스를 return 하는 함수

할당문 왼쪽에 사용할 수 있습니다.
정적 변수를 반환합니다.
새 객체를 만들지 않습니다.

참조자를 리턴한다는 거의 의미

#include <iostream>

using namespace std;

double vals[] = { 1,2,3,4,5 };

double& setValues(int i) {
	return vals[i];
}

int main() {
	for (int i = 0; i < 5; i++) 
		cout << vals[i] << endl;
	setValues(1) = 6;

	for (int i = 0; i < 5; i++)
		cout << vals[i] << endl;
	
}

객체 자체를 return하여 값을 바꿔줄 수 있어 단순히 value를 받아 scope내에서만 값을 바꿔주는 것과는 다르다.

profile
컴퓨터와 교육 그사이 어딘가

0개의 댓글