[C++] 생성자와 소멸자 2
생성자와 소멸자 2
인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다.
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!
기본 생성자를 만들지 않는 경우
#include <iostream>
using namespace std;
class Knight
{
public:
Knight(int hp)
{
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;
this->_hp = 1; // this는 자기 자신을 가리킨다
cout << "Die" << endl;
}
public:
// 멤버 변수
int _hp;
int _attack;
int _posY;
int _posX;
};
void Knight::Move(int y, int x)
{
_posY = y;
_posX = x;
cout << "Move" << endl;
}
void Knight::Attack()
{
}
int main()
{
Knight k1;
k1._hp = 100;
k1._attack = 10;
k1._posY = 0;
k1._posX = 0;
return 0;
}
실행화면
하지만 아래와 같이 고치면 잘 실행된다.
int main()
{
Knight k1(100);
k1._hp = 100;
k1._attack = 10;
k1._posY = 0;
k1._posX = 0;
return 0;
}
- Knight k1(100)으로 변경되어 Knight(int hp)가 호출된다.
연습 예시
#include <iostream>
using namespace std;
class Knight
{
public:
//// [1] 기본 생성자 (인자가 없음)
//Knight()
//{
// cout << "Knight() 기본 생성자 호출" << endl;
// _hp = 100;
// _attack = 10;
// _posX = 0;
// _posY = 0;
//}
//// [2] 복사 생성자 : 자기 자신의 클래스 참조 타입을 인자로 받음.
//// 일반적으로 '똑같은' 데이터를 지닌 객체가 생성되길 기대한다
//Knight(const Knight& knight)
//{
// _hp = knight._hp;
// _attack = knight._attack;
// _posX = knight._posX;
// _posY = knight._posY;
//}
Knight(int hp)
{
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;
this->_hp = 1; // this는 자기 자신을 가리킨다
cout << "Die" << endl;
}
public:
// 멤버 변수
int _hp;
int _attack;
int _posY;
int _posX;
};
void Knight::Move(int y, int x)
{
_posY = y;
_posX = x;
cout << "Move" << endl;
}
void Knight::Attack()
{
}
int main()
{
Knight k1(100);
// k1._hp = 100;
k1._attack = 10;
k1._posY = 0;
k1._posX = 0;
Knight k2(k1);
k1.Move(2, 2);
k1.Attack();
k1.Die();
return 0;
}
실행화면
명시적인 용도로만 사용 - explicit 키워드
#include <iostream>
using namespace std;
class Knight
{
public:
// [1] 기본 생성자 (인자가 없음)
Knight()
{
cout << "Knight() 기본 생성자 호출" << endl;
_hp = 100;
_attack = 10;
_posX = 0;
_posY = 0;
}
// [2] 복사 생성자 : 자기 자신의 클래스 참조 타입을 인자로 받음.
// 일반적으로 '똑같은' 데이터를 지닌 객체가 생성되길 기대한다
/*Knight(const Knight& knight)
{
_hp = knight._hp;
_attack = knight._attack;
_posX = knight._posX;
_posY = knight._posY;
}*/
// [3] 기타 생성자
// 이 중에서 인자를 1개만 받는 [기타 생성자]를
// [타입 변환 생성자]라고 부르기도 함
// 명시적인 용도로만 사용할 것! explicit
explicit Knight(int hp)
{
cout << "Knight(int) 기본 생성자 호출" << endl;
_hp = hp;
_attack = 10;
_posX = 0;
_posY = 0;
}
Knight(int hp, int attack, int posX, int posY)
{
_hp = hp;
_attack = 10;
_posX = 0;
_posY = 0;
}
// 소멸자
~Knight()
{
cout << "Knight() 소멸자 호출" << endl;
}
// 멤버 함수 선언
void Move(int y, int x);
void Attack();
void Die()
{
_hp = 0;
this->_hp = 1; // this는 자기 자신을 가리킨다
cout << "Die" << endl;
}
public:
// 멤버 변수
int _hp;
int _attack;
int _posY;
int _posX;
};
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;
}
int main()
{
Knight k1(100, 10, 0, 0);
// k1._hp = 100;
k1._attack = 10;
k1._posY = 0;
k1._posX = 0;
Knight k2(k1); // 복사 생성자로 만들어진다.
Knight k3 = k1; // 복사 생성자로 만들어진다.
Knight k4; // 생성자
k4 = k1; // 복사
k1.Move(2, 2);
k1.Attack();
k1.Die();
// 암시적 형변환 -> 컴파일러가 알아서 바꿔치기
int num = 1;
float f = (float)num; // 명시적 < 우리가 코드로 num을 float 바구니에 넣으라고 주문하고 있음
// float f = num; // 암시적 << 별말 안 했는데 컴파일러가 알아서 처리하고 있음
double d = num; // 암시적 << 별말 안 했는데 컴파일러가 알아서 처리하고 있음
Knight k5;
k5 = (Knight)1; // 명시적. 위에 explicit를 붙였기 때문에 명시적으로 사용해야만 함.
HelloKnight((Knight)5); // 명시적. 위에 explicit를 붙였기 때문에 명시적으로 사용해야만 함.
return 0;
}
핵심부분
explicit Knight(int hp)
{
cout << "Knight(int) 기본 생성자 호출" << endl;
_hp = hp;
_attack = 10;
_posX = 0;
_posY = 0;
}
int main()
{
float f = (float)num; // 명시적 < 우리가 코드로 num을 float 바구니에 넣으라고 주문하고 있음
// float f = num; // 암시적 << 별말 안 했는데 컴파일러가 알아서 처리하고 있음
double d = num; // 암시적 << 별말 안 했는데 컴파일러가 알아서 처리하고 있음
Knight k5;
k5 = (Knight)1; // 명시적. 위에 explicit를 붙였기 때문에 명시적으로 사용해야만 함.
HelloKnight((Knight)5); // 명시적. 위에 explicit를 붙였기 때문에 명시적으로 사용해야만 함.
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#include <iostream>
using namespace std;
class Monster
{
private:
string Name = "허수아비";
int Hp = 10000;
public:
void Damaged(int atk)
{
printf("%i 데미지를 입었습니다. \n", atk);
Hp -= atk;
printf("남은 Hp : %i \n", Hp);
}
};
class Character
{
protected:
string Name= "";
unsigned Lv = 0;
unsigned Hp = 0;
unsigned Atk = 0;
public:
Character() { cout << "캐릭터 생성자 호출" << endl; }
// 생성자 리스트
// 생성자를 실행하기 전에 실행할 명령을 등록합니다.
// 생성자 뒤에 : 을 작성하여 사용합니다.
// 받은 인자 값으로 멤버들을 먼저 초기화 시킨 후 생성자의 정의를 실행합니다.
Character(string name, unsigned lv, unsigned hp, unsigned atk) : Name(name), Lv(lv), Hp(hp), Atk(atk)
{
Name = name;
Lv = lv;
Hp = hp;
Atk = atk;
}
~Character() { cout << "캐릭터 소멸자 호출" << endl; }
public:
void PrintCharacter() const
{
cout << "Name : " << Name << endl;
cout << "Lv : " << Lv << endl;
cout << "Hp : " << Hp << endl;
cout << "Atk : " << Atk << endl;
}
int Attack()
{
printf("%s가 공격합니다. \n", Name.c_str());
return Atk;
}
};
class Warrior : public Character
{
private :
int STR;
public:
Warrior() { cout << "워리어 생성자 호출" << endl; }
// 상속에서 생성자는 최상위 기반클래스부터 최하위 파생 클래스 순서로 호출됩니다.
// 생성자 리스트
// 생성자를 실행하기 전에 실행할 명령을 등록합니다.
// 생성자 뒤에 : 을 작성하여 사용합니다.
// 기반 클래스의 생성자를 지정할 수 있습니다.
Warrior(string name, unsigned lv, unsigned hp, unsigned atk, int str) : Character(name, lv, hp, atk)
{
STR = str;
}
~Warrior() { cout << "워리어 소멸자 호출" << endl; }
// 상속에서 소멸자는 최하위 기반클래스부터 최상위 기반 클래스 순서로 호출됩니다.
public:
int Skill()
{
printf("%s가 스킬을 사용합니다. \n", Name.c_str());
return Atk + STR;
}
// 기반 클래스의 매서드를 재정의 합니다.
// 이를 오버라이딩이라 합니다.
void PrintCharacter() const
{
// Warrior 형식에선 Character 형식의 구조를 가지고 있고
// Warrior 의 PrintCharacter가 아닌
// Character 형식에 있는 PrintCharacter를 호출해줄 수 있습니다.
Character::PrintCharacter();
cout << "STR : " << Atk << endl;
}
};
int main()
{
//character character = character("캐릭터", 1, 10, 10);
//character.printcharacter();
// Warrior 형태의 객체를 동적할당하고 동적할당한 주소를 저장합니다.
//Warrior warrior = new Warrior("워리어", 1, 100, 10, 1);
//warrior.PrintCharacter();
//warrior.Attack();
//warrior.Skill();
// warrior.Lv // protected로 설정한 멤버이므로 상속받은 클래스가 아닌 외부에서 사용 불가
// 업 캐스팅 : 파생 클래스의 형식을 기반 클래스의 형시긍로 가리키는 것을 말합니다.
Character* warrior = new Warrior("워리어", 1, 100, 10, 1);
warrior->PrintCharacter();
((Warrior*)warrior)->PrintCharacter();
// 다운 캐스팅 : 기반 클래스의 형식을 파생 클래스의 형시긍로 가리키는 것을 말합니다.
//Character* character = new Character("워리어", 1, 100, 10, 1);
//Warrior* down = (Warrior*)character;
//down->PrintCharacter();
delete warrior;
warrior = nullptr;
return 0;
};
|
cs |
'⭐ Programming > C++' 카테고리의 다른 글
[C++] 은닉성 (0) | 2022.04.04 |
---|---|
[C++] 상속성 (0) | 2022.04.04 |
[C++] 생성자와 소멸자 (0) | 2022.04.04 |
[C++] 객체지향 (0) | 2022.04.03 |
[C++] 파일 분할 관리, #ifndef, #endif (0) | 2022.04.03 |
댓글
이 글 공유하기
다른 글
-
[C++] 은닉성
[C++] 은닉성
2022.04.04 -
[C++] 상속성
[C++] 상속성
2022.04.04 -
[C++] 생성자와 소멸자
[C++] 생성자와 소멸자
2022.04.04 -
[C++] 객체지향
[C++] 객체지향
2022.04.03