타입 변환 #2

이승덱·2021년 7월 21일

CPP

목록 보기
37/70
#include <iostream>

#include<iomanip>

using namespace std;

class Knight {

public:

 int _hp=0;

};

class Item {

public:

 Item() {

 cout << "Item()" << endl;

 }

 Item(int itemType) : _itemType(itemType) {

 }

 Item(const Item& item) {

 cout << "Item(const Item&)" << endl;

 }

 virtual ~Item() {

 cout << "~Item()" << endl;

 }

public:

 int _itemType = 0;

 int _itemDbId = 0;

 char _dummy[4096] = {}; //비대해진 아이템 클래스를 나타냄

};

enum ItemType {

 IT_WEAPON = 0,

 IT_ARMOR = 1,

};

class Weapon :public Item {

public:

 Weapon() : Item(IT_WEAPON){

 cout << "Weapon()" << endl;

 _damage = rand() % 100;

 }

 ~Weapon() {

 cout << "~Weapon()" << endl;

 }

public:

 int _damage;

};

class Armor :public Item {

public:

 Armor() : Item(IT_ARMOR) {

 cout << "Armor()" << endl;

 _defence = rand() % 100;

 }

 ~Armor() {

 cout << "~Armor()" << endl;

 } 

public:

 int _defence;

};

void TestItem(Item item) {

 //복사 생성자를 호출함

}

void TestItemPtr(Item* item) {

 //생성자 호출 X 원격으로 조종

}

int main()

{

 {

 //Stack [ 주소 ] -> Heap [ _hp(4) ]

 Knight* knight = new Knight();

 //암시적으로는 NO

 //Item* item=Knight; -> X

 //명시적으로는 OK

 //Stack [ 주소 ]

 //Knight는 4바이트를 가지고 있지만 Item으로 명시적 변환을 해주기 때문에

 //이상한 주소를 사용하게 된다.

 //이러한 위험한 캐스팅는 엄청난 오류를 만들어낼 수 있다;;

 //Item* item = (Item*)knight;

 //item->_itemType = 2; //유효한 데이터의 변동

 //item->_itemDbId = 1; //유효하지 않음

 }

 //자식 부모 변환 테스트

 //암시적 변환 O

 {

 Weapon* weapon = new Weapon();

 //무기는 아이템인가? OK

 Item* item = weapon;

 delete weapon;

 }

 //부모 -> 자식 변환 테스트

 //암시적 변환 X

 {

 Item* item = new Item();

 //아이템은 무기인가? NO

 //잘못된 메모리를 조작함

 //Weapon* weapon = (Weapon*)item;

 //weapon->_damage = 10;

 delete item;

 }

 //명시적으로 타입 변환할 때는 항상 조심해야한다!

 //의문점:

 // -> 그럼 암시적으로 될 때는 안전한가?

 // -> 평생 명시적으로 타입 변환(캐스팅)은 안 하면 되는거 아님?

 srand((unsigned int)time(nullptr));

 Item* inventory[20] = {};

 //서로 다른 자식클래스를 부모 클래스로 관리를 할 수 있다

 for (int i = 0;i < 20;i++) {

 int randValue = rand() % 2;

 switch (randValue)

 {

 case 0:

 inventory[i] = new Weapon();

 break;

 case 1:

 inventory[i] = new Armor();

 break;

 default:

 break;

 }

 }

 for (int i = 0;i < 20;i++) {

 Item* item = inventory[i];

 if(item==nullptr)

 continue;

 if (item->_itemType == IT_WEAPON) {

 //뭉뚱그려 관리하던 객체를 다시 원래 클래스로 되돌려야 할 경우

 //명시적 타입 변환이 필수적

 Weapon* weapon = (Weapon*)inventory[i];

 cout << "Weapon Damage is "<<weapon->_damage << endl;

 delete(item);

 }

 }

 //*********************매우 중요*************************************

 //부모의 소멸자를 virtual로 선언할 경우 가상함수 테이블을 통해 원래 객체의 소멸자도 함께 호출됨

 //결론

 //포인터 vs 일반타입의 차이를 숙지해야함

 //포인터 사이의 타입 변환을 할 때는 매우매우 조심하자!(특히 명시적 변환)

 //부모 자식 관계에서 부모 클래스의 소멸자에 까먹지 말고 virtual을 붙이자!

 return 0;

}
profile
공부 기록용 블로그입니다

0개의 댓글