오븐 노트

[C++] 생성자와 소멸자 #1 ~ 2 본문

Develop/C++

[C++] 생성자와 소멸자 #1 ~ 2

오 븐 2022. 9. 7. 18:59
#include <iostream>
using namespace std;

// [생성자(Constructor)]와 [소멸자(Destructor)]
// 클래스에 '소속'된 함수들을 멤버 함수라고 함
// 이 중에서 굉장히 특별한 함수 2종이 있는데, 바로 [시작]과 [끝]을 알리는 함수들
// - 시작(탄생) -> 생성자 (여러개 존재 가능)
// - 끝(소멸) -> 소멸자 (오직 1개만)

// [암시적(Implicit) 생성자]
// 생성자를 명시적으로 만들지 않으면,
// 아무 인자도 받지 않는 [기본 생성자]가 컴파일러에 의해 자동으로 만들어짐.
// -> 그러나 우리가 명시적(Explicit)으로 아무 생성자 하나 만들면,
// 자동으로 만들어지던 [기본 생성자]는 더 이상 만들어지지 않음.

// class는 일종의 설계도, 반환 타입이 없다
class Knight
{
public:
	// [1] 기본 생성자 (인자가 없음)
	Knight() // 반환 타입 X, Knight가 호출될때 무조건 실행됨
	{
		cout << "Knight() 기본 생성자 호출" << endl;

		_hp = 100;
		_attack = 10;
		_posX = 0;
		_posY = 0;
	}

	// [2] 복사 생성자 (자기 자신의 클래스 참조 타입을 인자로 받음)
	// (일반적으로 '똑같은' 데이터를 지닌 객체가 생성되길 원할때 사용
	// 인자로 받는 데이터를 조작할 일이 없으므로 const로 받음
	Knight(const Knight& knight)
	{
		_hp = knight._hp;
		_attack = knight._attack;
		_posX = knight._posX;
		_posY = knight._posY;
	}

	// [3] 기타 생성자
	// 이 중에서 인자를 1개만 받는 [기타 생선자]를
	// [타입 변환 생성자] 라고도 함
	Knight(int hp) // 절대 누락해서는 안되는 데이터를 생성자에 넣는것을 고려할 수 있다.
	{
		cout << "Knight(int) 생성자 호출" << endl;
		_hp = hp;
		_attack = 10;
		_posX = 0;
		_posY = 0;
	}

	// [타입 변환 생성자]를 명시적인 용도로만 사용할 것
	explicit Knight(int hp) // 절대 누락해서는 안되는 데이터를 생성자에 넣는것을 고려할 수 있다.
	{
		cout << "Knight(int) 생성자 호출" << endl;
		_hp = hp;
		_attack = 10;
		_posX = 0;
		_posY = 0;
	}

	// [3] 기타 생성자
	Knight(int hp, int attack, int posX, int posY)
	{
		cout << "Knight(int) 생성자 호출" << endl;
		_hp = hp;
		_attack = 10;
		_posX = 0;
		_posY = 0;
	}

	// 소멸자
	~Knight()
	{
		cout << "Knight() 소멸자 호출" << endl;
	}

	//멤버 함수 선언
	void Move(int y, int x);
	void Attack();

	void Die()
	{
		_hp = 0;
		cout << "Die" << endl;
	}

public:
	// 멤버 변수
	int _hp;
	int _attack;
	int _posY;
	int _posX;
};

void Move(Knight* knight, int y, int x) // 일반 함수 버전
{
	knight->_posY = y;
	knight->_posX = x;
}

void Knight::Move(int y, int x) // 멤버 함수 버전
{
	_posY = y;
	_posX = x;
	cout << "Move" << endl;
}

void Knight::Attack()
{
	cout << "Attack : " << _attack << endl;
}

void HelloKnight(Knight k)
{
	cout << "Hello Knight" << endl;
}

// Instantiate 객체를 만든다
int main()
{
	Knight k1(100, 10, 0, 0); // [3] 기타 생성자
	//k1._hp = 100;
	k1._attack = 10;
	k1._posY = 0;
	k1._posX = 0;

	Knight k2(k1); // [2] 복사 생성자 사용

	Knight k3 = k1; // [2] 복사 생성자 사용

	Knight k4; // [1] 기본 생성자 사용
	k4 = k1; // k4에 k1을 복사해달라는 요청이므로 복사 생성자와는 다름

	k1.Move(2, 2); // 멤버 함수 버전
	k1.Attack();
	k1.Die();

	// 암시적 형변환 -> 컴파일러가 알아서 바꿔치기
	int num = 1;
	float f = (float)num; // 명시적 < 우리가 코드로 num을 float 바구니에 넣으라고 주문
	double d = num; // 암시적 << 별말 안했는데 컴파일러가 알아서 처리하고 있음

	Knight k5;
	k5 = 1; // 암시적 형변환

	HelloKnight(5); // 암시적 형변환 때문에 int형 5가 의도치 않게 Knight형 타입 변환 생성자로 생성된다
	
	k5 = (Knight)1; // 명시적 형변환

	HelloKnight((Knight)5); // 명시적 형변환

	return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

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

[C++] 은닉성  (0) 2022.09.21
[C++] 상속성  (0) 2022.09.20
[C++] 객체지향의 시작  (0) 2022.09.05
[C++] 파일 분할 관리  (0) 2022.08.29
[C++] 연습문제 (달팽이)  (0) 2022.08.22