절차(procedural)지향 프로그래밍
프로그램 : 데이터 + 가공(로직, 동작)
객체란? 플레이어, 몬스터, GameRoom
Knight를 설계해보자
// class는 일종의 설계도
class Knight
{
public:
// 멤버 함수 선언
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)
{
push ebp
mov ebp,esp
sub esp,0C0h
...
knight->posY = y;
mov eax,dword ptr [knight]
mov ecx,dword ptr [y]
mov dword ptr [eax+8],ecx
knight->posX = x;
mov eax,dword ptr [knight]
mov ecx,dword ptr [x]
mov dword ptr [eax+0Ch],ecx
}
void Knight::Move(int y, int x)
{
push ebp
mov ebp,esp
sub esp,0CCh
...
mov dword ptr [this],ecx
...
posY = y;
mov eax,dword ptr [this]
mov ecx,dword ptr [y]
mov dword ptr [eax+8],ecx
posX = x;
mov eax,dword ptr [this]
mov ecx,dword ptr [x]
mov dword ptr [eax+0Ch],ecx
cout << "Move" <<endl;
...
}
...
add esp,0CCh
cmp ebp,esp
call __RTC_CheckEsp (03512A8h)
mov esp,ebp
pop ebp
ret 8
void Knight::Attack(int y, int x)
{
cout << "Attack : " << attack << endl;
}
// Instantiate 객체를 만든다!
int main()
{
Knight k1;
k1.hp = 100;
k1.attack = 10;
k1.posY = 0;
k1.posX = 0;
Knight k2;
k2.hp = 80;
k2.attack = 5;
k2.posY = 1;
k2.posX = 1;
Move(&k1, 2, 2);
push 2
push 2
lea eax,[k1]
push eax
call Move (03511DBh)
add esp,0Ch
k1.Move(2, 2);
push 2
push 2
lea ecx,[k1] // load effective address
call Knight::Move (0351235h)
k1.Attack();
lea ecx,[k1]
call Knight::Attack (03510A5h)
k1.Die();
lea ecx,[k1]
call Knight::Die (0351271h)
return 0;
}
// sizeof(k1) : 16 (멤버 변수 크기만큼)
&k1
00000064
0000000a
00000000
00000000
멤버 함수 호출 전 레지스터에 객체의 주소를 복사한다.
함수 내부에서 this라는 포인터(아마 스택에 할당)에 레지스터에 담긴 주소값을 복사한다.
this라는 포인터는 일반 함수에서의 인자로 받은 주소값처럼 사용된다.
객체의 크기는 멤버 변수 크기와 연관이 있다. 멤버 함수는 연관없다. 멤버 함수도 결국 내부적으로는 일반 함수와 큰 차이가 없는 것 같다.
C에서는 struct와 class가 다르지만, C++에서는 거의 비슷하다.