객체지향 (OOP Object Oriented Programming)
다형성(Polymorphism = Poly + morph) = 겉은 똑같은데, 기능이 다르게 동작한다
void MovePlayer(Player* player)
{
player->Move();
}
void MoveKnight(Knight* knight)
{
knight->Move();
}
int main()
{
Player p;
MovePlayer(&p); // 플레이어는 플레이어다? YES
//MoveKnight(&p); // 플레이어는 기사다? NO
Knight k;
MoveKnight(&k); // 기사는 기사다? YES
MovePlayer(&k); // 기사는 플레이어다? YES
return 0;
}
바인딩(Binding) = 묶는다
일반 함수는 정적 바인딩을 사용
동적 바인딩을 원한다면? -> 가상 함수 (virtual function)
가상 함수는 virtual 키워드를 생략하여 오버라이딩 하더라도 여전히 가상 함수다!
class Player
{
public:
Player()
{
_hp = 100;
}
virtual void VMove() {}
virtual void VDie() {}
private:
int _hp;
}
class Knight : public Player
{
public:
Knight()
{
_stamina = 100;
}
virtual void VMove() {}
virtual void VDie() {}
private:
int _stamina;
}
class Mage : public Player
{
public:
virtual void VMove() {}
}
void MovePlayer(Player* player)
{
player->VMove();
player->VDie();
}
Knight k;
MovePlayer(&k);
&k 주소를 열어보면
002b9b4c <- 무언가 추가됨.
00000064
00000064
실제 객체가 어떤 타입인지 어떻게 알고 알아서 가상함수를 호출해준걸까?
.vftable [] 4바이트(32) 8바이트(64)
[VMove][VDie]
void MovePlayer(Player* player)
{
player->VMove();
player->VDie();
}
player 주소를 열어보면
00b49b60 <- virtual function table 주소
00000064
00000064
player->VMode();
mov eax,dword ptr [player]
mov edx,dword ptr [eax]
...
mov eax,dword ptr [edx]
call eax
vftable 주소로 가보면
0x00b49b60 00b414f6 <- eax에 들어있는 값 (Knight의 VMove() 주소)
0x00b49b64 00b41523 <- Knight의 VDie() 주소
player->VDie();
mov eax,dword ptr [player]
mov edx,dword ptr [eax]
...
mov eax,dword ptr [edx+4]
call eax
그렇다면 vftable 주소를 채우는 주체는 누구인가?
Knight k;
lea ecx, [k]
call Knight::Knight (...)
Knight()
...
pop ecx
mov dword ptr [this],ecx
...
mov ecx,dword ptr [this]
call Player::Player (...)
mov eax,dword ptr [this]
mov dword ptr [eax],offset Knight::'vftable' (...)
{
_stamina = 100;
}
생성자의 선처리 영역에서 클래스의 vftable 주소를 대입한다.
(부모 클래스 생성자에서의 vftable 주소를 자식 클래스 생성자에서 덮어쓴다.)
순수 가상 함수 : 구현은 없고 인터페이스만 전달하는 용도
virtual void VAttack() = 0;
재정의를 해야만 하도록 강제한다.
추상 클래스 : 순수 가상 함수가 1개 이상 포함되면 바로 추상 클래스로 간주
상속을 통해 순수 가상 함수를 구현해야 객체를 만들 수 있다.
virtual void VAttack() { }