본문 바로가기

교육 노트/C++ 심화강의

[C++ 때려잡기] C++ 심화강의 13 다형성, 다운 캐스팅 업 캐스팅

2018/08/27 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 1 객체 지향 프로그래밍과 클래스

2018/08/27 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 2 접근 한정자

2018/08/27 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 3 생성자와 소멸자

2018/08/29 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 4 복사 생성자와 깊은 복사

2018/08/29 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 5 this 포인터

2018/08/29 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 6 Class 선언과 정의

2018/08/29 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 7 inline 함수

2018/08/31 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 8 Friend function, friend class

2018/08/31 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 9 연산자 오버로딩, chaining

2018/08/31 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 10 클래스의 핵심 상속

2018/08/31 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 11 다중 상속과 가상 상속

2018/08/31 - [교육 노트/C++ 심화강의] - [C++ 때려잡기] C++ 심화강의 12 오버라이딩 (overriding)


기존에 내 캐릭터에 칼을 가지도록 하였다.


아근데 칼만 쓸것은 아니니까

총도 넣고 활도 넣고 지팡이도넣고...

와 그러면 character는 맴버변수로 게임에쓰이는 모든 무기를 다 가지고 있어야한다.

메모리를 미친듯이 잡아먹는다.


공격할때마다 if문 으로 어떤무기인지 검사하고 해당 무기를 써줘야한다

미친듯이 느려진다.


해결방안을 알아보기전에


캐스팅에대하여 알아보자


1. 캐스팅

int를 float로 float를 int로 ... 과 같은 것을 캐스팅이라고 했다.


그렇다면 우리가 만든 클래스를 다른 클래스로 바꾸는것이 가능할까?

클래스는 사실상 불가능하다.

그러나 포인터는 가능하다.

무슨소리냐하믄..



Gun/ Knife / Bow를 weapon으로 바꾸면 위로가는 캐스팅이라고 하여 업 캐스팅 (up casting) 이다.

아까 포인터를 통하여 가능하다고 했는데

다음과 같다.


이런식이다.

즉 GUN을 weapon으로 바꾸었다기 보다는

메모리에는 GUN 고대로 존재하되 (동적할당)

그 시작점을 가르키는 포인터를 부모로 가르키겠다는 의미이다.

다시 말하면 부모 포인터로 자식 객체를 가르키겠다는 의미이다.


반대로

weapon을 gun/knife/bow로 바꾼다면 그것은 위에서 아래로 바꾸는 캐스팅이므로 다운 캐스팅 (down casting) 이다.

Gun* g = new Weapon();


뭐 이렇게 하거나 (해당 코드는 쓸수없다.)


Weapon* w = new Weapon();

Gun* g = (Gun*)w;

뭐 이런식으로 바꾸면 다운캐스팅일것이다


일반적으로 부모 포인터를 통하여
자식 객체에 접근하는 (업 캐스팅) 은 허용되지만
자식 포인터로 부모객체를 가르키는경우는
 허용되지않는다.


아니뭐 강제로 때려박으면 가르키기야 하겠지만 (2번째) 제대로 사용할수없다.


자식객체가 만들어질때 부모 객체도 만들어진다고 했었는데.

따라서 자식객체는 부모객체를 포함하고 있는 사이즈를 가지고있다.

따라서 자식 객체 포인터라면 컴파일러가

아 이 포인터를 따라가면 요기부터 요기까지가 이놈이 차지하는 공간이것구나~ 하고 생각하는데

자식 포인터가 부모 객체를 가르키면

아 요기부터 요기까지가 이놈 공간이라고 생각하고 사용하려는데

그공간에는 아무것도 안들어있는 경우가 생긴다.

Bow* b; 라고 선언되었어서

b->setReach(5); 뭐 이런식으로 썻는데 거기있는 객체가 bow가 아니라 weapon이어 가지고 setReach 함수도 없고 reach 변수도 없으면 

다운캐스팅은 강제로 했다한들 저 뒤에 메모리공간을 그냥 강제로 사용하는것이다. 저기에 어떤 메모리가 있었는지도 모르지만 강제로 사용 불가능해야 하는 메모리를 써버리는것이라 프로그램에 어떤 문제가 발생할지 조차 모르는것이다.



그러나 가능한 경우가 있는데

요럴때 한정이다. gun이 업케스팅 되어 weapon포인터가 gun을 가르킬때만 다시 gun포인터로 바꾸어주는경우다

다이나믹 캐스팅에서 다이나믹은  동적할당의 동적(dynamic)이고 역시 런타임중에 이루어진다.

즉 컴파일러가 모르는 동적할당을 통하여 다운캐스팅을 했을수도 있으니까~

한번 바꿔보고~ 되면  동적으로 다시 바꿔주자~ 라는 의미이다.

안되면 0 (NULL) 을 반환한다. 즉 g를 검사해서 0이면 다운캐스팅 실패니까 안쓰면 되고

0 아니면 쓰면 된다.

그냥 일반 (Gun*) 로 캐스팅 하는경우와 다른경우는

미리 캐스팅성공 여부를 알수있으므로 개발자가 에러뿜뿜상황을 미연에 방지할수있는것이다.




자 지금까지 부모와 자식간의 캐스팅 방법을 알아보았다.

근데 부모 자식간에 포인터를 바꿔서 어디서 쓰냐고?



2, 다형성


방금 업캐스팅은 된다고 했다. 즉 부모 포인터로 자식 객체는 가르킬수 있으니 부모 포인터를 만들고 이를 이용하여 그때그때 원하는 자식 객체를 만들어(동적할당) 하여 그 객체를 가르키게 하면 된다.

그리고 weapon-> attack() 하여 함수를 호출할수있다.

이렇게 부모 포인터 하나로 다양한 클래스를 만들고 가르킬수있다.

이런것을 다형성이라고 한다.



또한 자식 객체에만 있는 함수를 부르고싶을때는

그때만 다운캐스팅 하여 호출하면된다

((Bow*)weapon)->setReach(5); 해서 그냥 확인도 안해보고 bow로 일단 캐스팅 해서 bow면 돌아가고 bow가 아니었다 하면 오류뿜뿜하게해서 프로그램이 꺼지도록하던가

아니면 다이나믹 캐스팅을 통하여 검사하던가 한 후에 호출하면 된다.


이제 weapon* 하나로 모든 무기를 만들수 있게 되었다!

그러나...


1. 다이나믹 캐스팅을 사용할수 없어요..

2. 오버라이딩했는데 적용이 안되요..


같은 문제가있다


다음 시간에 해결해보도록 하겠다.


.





728x90