오븐 노트

[C++] 다형성 #1 ~ 2 본문

Develop/C++

[C++] 다형성 #1 ~ 2

오 븐 2022. 9. 28. 18:53
#include <iostream>
using namespace std;

// 다형성 (Polymorphism == Poly + morph) == 겉은 같지만 기능이 다르게 동작한다.
// - 오버로딩 (Overloading) == 함수 중복 정의 == 함수 이름의 재사용
// - 오버라이딩 (Overriding) == 재정의 == 부모 클래스의 함수를 자식 클래스에서 재정의

// 바인딩 (Binding) = 묶는다 -> 어떤 함수를 호출해야하는지 해당 함수와 주소를 매핑하여 연결해주는 역할
// - 정적 바인딩 (Static Binding) : 컴파일 시점에 결정
// - 동적 바인딩 (Dynamic Binding) : 실행 시점에 결정 ※ 단골 질문 ※

// 일반 함수는 정적 바인딩을 사용
// 동적 바인딩을 원한다면? -> 가상 함수 (virtual function)

// 실제 객체가 어떤 타입인지 어떻게 알고 알아서 가상함수를 호출해주는가?
// - 가상 함수 테이블 (vftable)

// vftable [] 4바이트(32) 8바이트(64)

// vftable의 주소 [VMove] [VDie]

// 순수 가상 함수 : 구현은 없고 인터페이스만 전달하는 용도로 사용하고 싶은 경우
// 추상 클래스 : 순수 가상 함수가 1개 이상 포함되면 바로 추상 클래스로 간주됨.
// - 직접적으로 객체를 만들 수 없게 됨. 오직 상속으로 구현해야 사용 가능해짐.

class Player
{
public:
    Player() // 기본 생성자 -> 생성자를 직접 만들어야지만 디스어셈블리 확인 시 해당 생성자를 호출하는 부분에서 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; // Player를 상속하면 반드시 해당 함수를 구현하여 사용하라는 명령

public:
    int _hp;
}

class Knight : public Player
{
public:
    Knight() // 기본 생성자 -> 생성자를 직접 만들어야지만 디스어셈블리 확인 시 해당 생성자를 호출하는 부분에서 Knight를 호출하고있다고 명시해주기 때문에 확인용으로 작성
    { // vftable을 생성하는 주체는 생성자이다.
        _stamina = 100;
    }

    void Move() { cout << :"Move Knight !" << endl; }
    
    // 가상 함수는 virtual을 제외하고 재정의를 하더라도 자상 함수이다.
    virtual void VMove() { cout << :"VMove Knight !" << endl; }
    virtual void VDie() { cout << :"VDie Knight !" << endl; }

    virtual void VAttack() { cout << :"VAttack Knight !" << endl; } // 순수 가상 함수를 재정의 후 구현해야지만 해당 class를 사용 가능해짐

public:
    int _stamina;
}

class Mage : public Player
{

public:
    int _mp;
}


// [ [ Player ] ] 1층
// [   Knight   ] 2층
// 공통적인 기능은 대부분 가상함수로 활용
void MovePlayer(Player* player) // 해당 함수 내에서는 매개변수에 들어오는 값이 Knight인지 Player인지 알 수 없다. // 기본적으로 Player에 정적 바인딩이 되어있음
{
    player->VMove();
    player->VDie();
}

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

int main()
{

    // Player p; // 순수 가상 함수를 선언하면서 스스로만을 선언 할 수 없게됨.
    // p.Move();
    // p.Move(100); // 오버로딩
    // MovePlayer(&p); // 플레이어는 플레이어다? Y
    // MoveKnight(&p); // 플레이어는 기사다? N // 자식요소에서 부모요소는 가능하지만 부모요소에서 자식요소는 불가능

    Knight k; // 순수 가상 함수를 상속받았으므로 반드시 재정의 해야 선언 가능.
    // k.Move();
    // MoveKnight(&k); // 기사는 기사다? Y
    MovePlayer(&k); // 기사는 플레이어다? Y

    return 0;
}

[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
 
C++ 카테고리의 글은 인프런 Rookiss님의 강의를 공부하며 정리하는 내용입니다.
이미 알고 있는 내용도 다시 정리 되어있을 수 있습니다.

 

모든 글은 제가 공부하기 위해 작성합니다.

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

[C++] 연산자 오버로딩 #1 ~ 2  (0) 2022.10.05
[C++] 초기화 리스트  (0) 2022.10.05
[C++] 은닉성  (0) 2022.09.21
[C++] 상속성  (0) 2022.09.20
[C++] 생성자와 소멸자 #1 ~ 2  (0) 2022.09.07