초 간단 Virtual의 이해(다형성)

다형성 : 객체지향 프로그래밍에서, polymorphism(“여러 개의 형태를 가진다”는 의미의 그리스어에서 유래됨)이란 특정한 심벌이나 연산자에 대해 상황이 다르면, 그 의미도 다르게 부여할 수 있는 특성을 말한다.

아마 대부분의 사람들이 객체지향에 대해공부할 때 다형성, 상속 등등의 의미는 많이 들어보셨겠지만 정작 다형성이 무엇인가? 그리고 실제로 어떻게 사용해야 하는가? 는 잘 모르실 것입니다..

이번에 회사에서 공부하면서, 어떤 분이 아주 쉽게 설명해 주셨기에, 한번 주저리 적어봅니다.

스타크래프트의 마린과 메딕을 생각해봅시다.
마린메딕을 통들어 유닛이라고 하면 이들의 좌표가 있고, 이들의 hp, 이들을 화면에 출력해주는 draw()함수, 이들의 행동을 처리하는 process()함수가 공통일 것입니다.
거기서 메딕은 mp를 가지고 있지요.

virtual이 없을 경우를 보죠.

<br />class Unit() // 부모 클래스는<br />{<br />&nbsp; int x,y,hp;<br />&nbsp; void process(){}<br />&nbsp; void draw(){}<br />}<br /><br />class 마린() : public Unit // 자식 클래스는<br />{<br />&nbsp; void process()<br />&nbsp; { // 마린의 행동 재정의<br />&nbsp; }<br />&nbsp; void draw()<br />&nbsp; {<br />&nbsp; &nbsp;&nbsp; // 마린을 그려주는 걸 재정의<br />&nbsp; }<br />}<br /><br />class 매딕() : public Unit<br />{<br />&nbsp; void process()<br />&nbsp; { // 메딕의 행동 재정의<br />&nbsp; }<br />&nbsp; void draw()<br />&nbsp; {<br />&nbsp; &nbsp;&nbsp; // 메딕을 그려주는 걸 재정의<br />&nbsp; }<br />}<br /><br />void main()<br />{<br />&nbsp; 마린 a[]; // 마린들<br />&nbsp; 메딕 b[]; // 메딕들<br />&nbsp; 마린[1].process();<br />&nbsp; 마린[1].draw();<br />.<br />.<br />.<br /><br />}<br />

수십만 마리의 메딕을 배열에 넣고 관리한다면 마린1은 마린[1]이고 메딕1은 메딕[1]이고.. 딱 봐도 관리가 쉽지는 않겠죠?

이제 virtual을 사용해 봅시다.

<br />#include&lt;stdio.h&gt;<br />#include&lt;iostream&gt;<br />#include&lt;list&gt;<br />#include&lt;algorithm&gt;<br /><br />class Unit<br />{<br />public:<br />&nbsp;int x,y,hp,num;<br />&nbsp;virtual inline void process(){printf("이건 가라\n");}<br />&nbsp;virtual inline void draw(){printf("이건 가라\n");}<br />};<br />class 마린 : public Unit<br />{<br />public:<br />&nbsp;마린(int a)<br />&nbsp;{<br />&nbsp; this-&gt;num = a; <br />&nbsp;}<br />&nbsp;void process()<br />&nbsp;{ // 마린의 행동 재정의<br />&nbsp; printf("%d번째 마린이 움직이다.\n",this-&gt;num);&nbsp; <br />&nbsp;}<br />&nbsp;void draw()<br />&nbsp;{<br />&nbsp; // 마린을 그려주는 걸 재정의<br />&nbsp; printf("나는 마린%d이다\n",this-&gt;num);<br />&nbsp;}<br />};</p>
<p>class 매딕 : public Unit<br />{<br />public:<br />&nbsp;매딕(int a)<br />&nbsp;{<br />&nbsp; this-&gt;num = a; <br />&nbsp;}<br />&nbsp;void process()<br />&nbsp;{ // 메딕의 행동 재정의<br />&nbsp; printf("%d번째 메딕이 움직이다.\n",this-&gt;num);<br />&nbsp;}<br />&nbsp;void draw()<br />&nbsp;{<br />&nbsp; // 메딕을 그려주는 걸 재정의<br />&nbsp; printf("나는 메딕%d이다\n",this-&gt;num);<br />&nbsp;}<br />};</p>
<p>void main()<br />{<br />&nbsp;std::list&lt;Unit*&gt; x;<br />&nbsp;std::list&lt;Unit*&gt;::iterator itor;<br />&nbsp;Unit *k;<br />&nbsp;k = new 마린(1);//1번째 마린<br />&nbsp;x.push_front(k);<br />&nbsp;k = new 매딕(1);//1번째 메딕<br />&nbsp;x.push_back(k);<br />&nbsp;k = new 마린(2);//2번째 마린<br />&nbsp;x.push_back(k);</p>
<p>&nbsp;for( itor = x.begin() ; itor != x.end() ;itor++)<br />&nbsp;{<br />&nbsp; (*itor)-&gt;process();<br />&nbsp; (*itor)-&gt;draw();<br />&nbsp; //printf("%d\n",itor-&gt;num);<br />&nbsp;}<br />

Virtual을 사용하여 상속을 받은 자식 객체는
Unit *k; // 부모형 포인터
k = new 마린(1); // 자식형으로 생성
이러한 정의가 가능하게 됩니다. 그리고 이를 부모 형의 list에 이를 넣음으로써 iterator를 통해
(*itor)->process();
(*itor)->draw();
이 부분 처럼 x라는 리스트를 가지고 손쉽게 스타크래프트의 유닛들의 행동의 관리가 가능하지요. (단순히 for문만으로!)

만약 파이어뱃이 있다면 단순히 클래스 하나의 추가를 통해, 기존 클래스는 건드릴 필요 없이 추가가 가능하겠지요? 게다가 관리도 심플하고..

이래서 사람들이 클래스를 사용한다고 합니다. 저는 경력이 짧아서 그렇다고 말씀드리기는 힘들지만, 이 설명을 듣고는 프로그래밍 ‘설계’를 보는 눈이 달라졌지요.

간단하지만, 좋은 설명이 되었으면 하는 바램입니다.