다형성

namu·2022년 7월 24일

객체지향 (OOP Object Oriented Programming)

  • 상속성
  • 은닉성 = 캡슐화
  • 다형성

다형성(Polymorphism = Poly + morph) = 겉은 똑같은데, 기능이 다르게 동작한다

  • 오버로딩(Overloading) = 함수 중복 정의 = 함수 이름의 재사용
  • 오버라이딩(Overriding) = 재정의 = 부모 클래스의 함수를 자식 클래스에서 재정의
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) = 묶는다

  • 정적바인딩(Static Binding) : 컴파일 시점에 결정
  • 동적 바인딩(Dynamic 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)

.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() { }

profile
안녕하세요

0개의 댓글