다형성

 

인프런 Rookiss님의 'Part1: C++ 프로그래밍 입문' 강의를 기반으로 정리한 필기입니다. 
😎[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강의 들으러 가기!

 

 


 

바인딩(Binding)  -  정적 바인딩,  동적 바인딩

 

바인딩(Binding)  = 묶는다.

   
정적 바인딩(Static Binding)   컴파일 시점에 결정
동적 바인딩(Dynamic Binding)   실행 시점에 결정

일반 함수는 정적 바인딩을 사용한다.

 

동적 바인딩을 원한다면? 

  • 가상 함수(virtual function)를 사용한다.

 


 

 

가상 함수 테이블 ( vftable ) 


그런데 실제 객체가 어떤 타입인지 어떻게 알고 알아서 가상함수를 호출해준걸까?
-  가상 함수 테이블 (vftable)

.vftable [] 4바이트(32비트 프로그램) 8바이트(64비트 프로그램)

[VMove] [VDie]


 

 

순수 가상함수,  추상 클래스

 

순수 가상 함수 : 구현은 없고, '인터페이스'만 전달하는 용도로 사용하고 싶을 경우


추상 클래스 : 순수 가상 함수가 1개 이상 포함되면 바로 추상 클래스로 간주
-  직접적으로 객체를 만들 수 없게 됨
-  아래의 경우 : Player클래스는 추상 클래스가 된다. 메인 함수에서 Knight클래스없이 Player클래스만 독립적으로 존재할 수 없다.

 


 

 

 

코드

 

#include <iostream>
using namespace std;

class Player{
public:
    Player() {  _hp = 100;  }
    void Move() { cout << "Move Player! " << endl; }
    //void Move(int a) { cout << "Move Player (int)! " << endl; }  // 오버로딩 예시
    virtual void VMove() { cout << "VMove Player! " << endl; }
    virtual void VDie() { cout << "VDie Player! " << endl; }
    
    virtual void VAttack() = 0; // 순수 가상 함수

public:
    int _hp;
};

class Knight : public Player // public Player. public 안 적으면 private으로 인식
{
public:

    Knight()
    {
        _stamina = 100;
    }
public:
    void Move() { cout << "Move Knight! " << endl; } // 재정의. 

    // 가상 함수는 재정의를 하더라도 가상 함수다!
    virtual void VMove() { cout << "VMove Knight! " << endl; }  
    virtual void VDie() { cout << "VDie Knight! " << endl; }  
    virtual void VAttack() { cout << "VAttack Knight! " << endl; }  

public:
    int _stamina;
};

class Mage : public Player
{
public:
    int _mp;
};

// [ [ Player ] ]
// [   Knight   ]
void MovePlayer(Player* player)
{
    player->VMove();
    player->VDie();
}

//void MoveKnight(Knight* knight)
//{
//    knight->Move();
//}

int main()
{
    Player p;
    
    Knight k;
    MovePlayer(&k); // Knight는 Player다? YES  // 자식 클래스에서 부모 클래스로 넘어가는건 자연스럽다

    return 0;
}

 

실행과정 Breakdown

void MovePlayer(Player* player)
{
    player->VMove();
    player->VDie();
}

 

MovePlayer 함수로 들어온 player의 주소를 까서 확인해보면 

  • 3개의 주소가 있다.
  • Player의 첫번째 주소에는 vftable의 주소가 있다.
  • Player의 두번째, 세번째 주소는 player->VMove()와 player->VDie()에 사용하는 player의 주소다.

  1. player의 포인터를 타고 eax에 들어간다. eax에 들어가는 데이터는 player에 저장된 주소(=3개의 주소: vftable의 주소 + player의 주소 2개)다.
  2. eax의 첫번째 값(=vftable의 주소 = 00b49b60)을 edx에 꺼내온다.
  3. edx값을 eax에 넘겨준다.
  4. call eax를 한다.

 

 

 


 

Knight 생성자의 선처리 부분

 

Knight 생성자의 선처리 부분

-  자기 자신의 vftable을 채워준다.

0939B60h을 타고가면 Knight의 VMove 함수와 VDie 함수 주소가 나온다.

0939B60h을 타고가면 Knight의 VMove 함수와 VDie 함수 주소가 나온다.

 

 

 

 

 

'⭐ Programming > C++' 카테고리의 다른 글

[C++] 연산자의 오버로딩 (Operator Overloading), 오버로딩 vs 오버라이딩  (0) 2022.04.05
[C++] 초기화 리스트  (0) 2022.04.05
[C++] 다형성 (Polymorphism)  (0) 2022.04.05
[C++] 은닉성  (0) 2022.04.04
[C++] 상속성  (0) 2022.04.04