연산자 오버로딩 1, 2

CJB_ny·2022년 8월 11일
0

C++ 정리

목록 보기
52/95
post-thumbnail
post-custom-banner

연산자 오버로딩 1

연산자 vs 함수

연산자는 피연산자의 개수/타입이 고정되어있다.

피연산자의 개수가 1개인 경우도 존재 (++a/a++)

연산자 오버로딩 하는 방법

  1. [연산자 함수] 를 정의 한다.

  2. 함수도 멤버함수 vs 전역함수가 존재하는 것 처럼, 연산자 함수도 두가지 방식으로 만들 수 있다.

사용예제

이렇게 만들 어 줄 수 있다.

이게 사실은

위에는 보기 편하라고 한것이고 아래처럼해도 아무런 상관이 없다.

멤버 연산자 함수 version

a op b 형태에서 왼쪽을 기준으로 실행된다.

a가 클래스여야 가능, a를 기준으로 "기준 피연산자"라고한다.

  • 한계 a가 클래스가 아니라면 사용을 못한다.


이런식의 버젼으로도 만들어 사용할 수 있다.

그런데

기준 피연산자의 위치를 바꾼다면 더이상 실행이 안된다는 단점이 존재한다.

대안은 뭐냐?

전역 연산자 함수 version

a op b 형태라면, a, b 모두를 연산자 함수의 피연산자로 만들어 준다.



이런 전역버젼으로 만들어서 다시 실행하면은 빌드가 통과를 한다.

그렇다면 전역 연산자 함수가 좋으니까 이것만 쓴다? ㄴㄴ

전자의 버젼 멤버 연산자 방법대로만 만들 수 있는 것들도 있기 때문에

두가지 다 알아야한다.

  • 무엇이 더 좋은가? => 그런거 없음.
    둘중 하나만 지원하는 경우도 있기 때문.

대표적으로 "대입 연산자" (a = b)는 "전역 연산자 version"

으로는 만들지 못한다.

먼저 클래스 내부에서

이렇게 대입 연산자를 만들어 주도록 하자.

그리고 Position pos5를 만들고 그다음 줄에서

Pos5 = 5;를 하면 operator = 가 호출된다.

그런데 햇갈릴 만한게

Position pos5 = 5;

를하게되면

생성자에 5라는 값을 넣는다는 것이다.


생성자와 소멸자
https://velog.io/@starkshn/%EC%83%9D%EC%84%B1%EC%9E%90%EC%99%80-%EC%86%8C%EB%A9%B8%EC%9E%90


즉,

class Position 
{
public:
	Position() // 기본 생성자
    :
    {}
    
    Position(int value) // 인자를 하나 받는 생성자.
    :
    {}
};

이상태에서

기타 생성자인 Position (int value) 생성자를 생성자로 호출한 것인데

이 "기타 생성자"는 == "타입 변환 생성자"라고도 한다.

궁금한점 🛫

#include <iostream>
using namespace std;

// 1. 타입 변환 생성자 테스트
class Player
{
public :
	int m_iHp;
	int m_iAttack;
	int m_iDefense;

public:
	Player()
		:
		m_iHp(100),
		m_iAttack(20),
		m_iDefense(5)
	{
		cout << "Player 기본 생성자!" << endl;
	}

	Player(int id)
		:
		m_iHp(200),
		m_iAttack(40),
		m_iDefense(10)
	{
		cout << "Player ID 받는 버젼 생성자!" << endl;
	}
};

class Knight : public Player
{
public:
	int m_iStat;

public:
	Knight()
		:
		m_iStat(10)
	{
		cout << "Knight 기본 생성자!" << endl;
	}
	Knight(int id)
		:
		Player(id),
		m_iStat(20)
	{
		cout << "Knight id 받는 버젼 생성자!" << endl;
	}

};

int main()
{
	Knight k1;
	k1 = 3;


	return 0;
}

현재 Knight k1을 만들게 되면은

k1의 주소(0x000000718D0FF688)는 이런값으로 안에 데이터들이 스택에 자리를 차지하게된다.

이후 k1 = 3; 를 하게되면

Knight k1은 스택에 할당되어있는데

타입 변환 생성자를 통해 만들어진 객체를

k1 = 3 해주었기 때문에

암시적 형변환으로 만들어진 객체를 대입연산자로 k1의 주소에

멤버 변수 하나하나를 다 덮어 쓴 형태이다?


인프 질문글

https://www.inflearn.com/course/%EC%96%B8%EB%A6%AC%EC%96%BC-3d-mmorpg-1/unit/62221?tab=community&q=620583&category=questionDetail


이거는 지금 생성되자마자 5로 초기화 되는 느낌이다.

5라는 인자를 받는 생성자를 찾게된다.

전역으로 operator = 를 만들어 주었을때는 당연히 안되는데

상식적으로 생각을 해보면 코드가 오른쪽에서 왼쪽으로 흐르는데

int x = 10; 이 10을 x에 대입을 하는 것인데

전역으로 operaetor = 왼쪽 피연산자가 오른쪽으로 흐르게 한다면

말이 안된다.

"대입"의 느낌을 생각해보면 된다.

-> 위험하다 문법적으로 막음.

연산자 오버로딩 2

원래 이런식으로도 동작을 하는데

이게 operator = 의 반환 타입이 참조라서 이런게 가능한 것이다.

그래서 this는 호출한 쪽의 주소이니까

이것에 접근 '*' 해서 그 자신을 참조로 반환을 한다.

복사 대입 연산자 ❗

용어가 햇갈린다.

복사 생성자 / 대입 연산자 / 복사 대입 연산자

복사 대입 연산자 : 대입 연산자 중, 자기 자신의 참조 타입을 인자로 받는 것.

이런 형태이기는 한데

매개변수로 자신과 동일한 타입으로 받아준다.

특별한 이유 (특별대우)

복사 생성자, 복사 대입 연산자 등 복사 시리즈가 특별 대우를 받는 이유는

말 그대로 객체가 "복사" 되길 원하는 특징이 있기 때문에.

이녀석을 직접적으로 만들어 주지않으면

"컴파일러가 알아서 만들어 준다."

복사 생성자와 차이점

생성자는 객체가처음 만들어 질 때 실행되는

탄생을 알리는 함수이다.

또한 생성자를 여러가지 버젼으로 만들 수 있는데

그중에서도 이런식으로 자기자신을 참조타입으로 받게 만들 수 있다.

Position k1;

Position k2 = k1;

Position k3(k1);

이런식으로 복사 생성자 코드 작성이 가능하다.

"복사 대입 연산자"와 는 다르다.

Position p1;

Position p2;

p2 = p1;

이게 복사 대입 연산자를 사용한 부분이다.

복사 생성자 / 복사 대입 연산자 는 클래스 내에서 구현해놓지 않으면

컴파일러가 알아서 만들어 준다.

67 => 복사 생성자

71 => 복사 대입 연산자.

참고사항

  1. 모든 연산자를 다 오버로딩 할 수는 없다
    ex) :: , . , .*

  2. 모든 연산자가 2개의 항이 있는 것은 아니다. ++, --가 대표적(단항 연산자)

증감 연산자

++ --

전위형 : ++a operator ++ ()

후위형 : a++ operator ++ (int)

이거 그냥 규칙임.

후위 같은 경우 미리 ret로 받아 증가시켜 준뒤,

증가되기 이전값을 뱉어 준다.

Position ret = *this; 복사 생성자로 만든다음에

this->_x++;, this->_y++; 해주고

복사생성자로 만들어진 ret를 반환한다.

지금 이 경우에는 굉장히 위험한 상황이다.

스택메모리의 주소값을 전달하는 것인데

ret는 operator++ 호출 종료되면 사라지는 메모리 값이기 때문이다.

operator ++

후위 연산자의 경우

전위와 후위의 코드는 이렇게 작성을 하고

대입연산자는 이런식으로 작성을해준다.

그런데 얼핏 보기에는 아무 문제가 없어보이지만

이런식으로 대입을 할려고하면 문제가 생긴다.

=> operator = 의 매개변수 값을 참조를 받을려고하는데

opaertor ++ 후위연산자의 경우 복사본을 전달해주기 때문에

발생하는 문제이다.

그래서 대입 연산자에다가 const를 붙여주어서 수정하지 않겟다~

라고 해주어야한다.

어지간해서는 수정할 일 없으면 const ref& 이거 셋트로 기억을 하면 좋다.

profile
https://cjbworld.tistory.com/ <- 이사중
post-custom-banner

0개의 댓글