[C++ 기초] 오버라이딩, 다형성

라멘커비·2023년 12월 29일
0

CPP 입문

목록 보기
13/25

다형성

🪙override, virtual

  • virtual 문법 : 자식이 만약 나와 완전히 동일한 함수를 구현한다면(override) 자식의 함수를 우선적으로 실행한다.
    • 부모에서는 virtual을 붙이고, override하는 자식의 함수에는 override를 명시한다. (override는 생략가능)
  • FightUnit에 있는 GetAtt()함수는 공격력을 알려준다. 자식인 Player의 GetAtt()를 override해서 기본 공격력 + 무기 공격력이 될 수 있도록 한다.
class FightUnit {
public:
	virtual int GetAtt() {
		return Att;
	}
private:
	int Att = 10;
};

class Monster :public FightUnit {

};

class Player :public FightUnit {
public:
	int WeaponAtt = 10;
protected:
	// override 붙여서 부모에게 물려받은 함수를 재구현한 함수라는 것을 명시한다. (안 붙여도 의도대로 동작됨)
	int GetAtt() override {
		return FightUnit::GetAtt() + WeaponAtt; // 여기서의 GetAtt()는 내 함수로 인식됨.
	}
};

🪙재귀, Stack overflow

  • Player 클래스 내 GetAtt 함수에서 부모의 공격력과 무기공격력을 더하고 싶었으나 그냥 GetAtt()로 호출하면 자기 자신의 함수로 인식된다. <- 재귀
  • 재귀호출되면서 Stack overflow가 발생하게 된다.
  • FightUnit::GetAtt()로 정확하게 부모의 함수를 불러오는 것으로 작성해서 해결할 수 있다.

🪙다형성

  • 아래 코드에서 Fight 함수에서 FightUnit 포인터를 인자로 받는다. main 함수에서는 Player와 Monster의 객체를 넣어줬다. 겉으로 볼 때는 FightUnit이지만 동작은 플레이어나 몬스터처럼 할 수 있다. 이런 점이 객체 지향의 다형성이다.
#include <iostream>

class FightUnit {
public:
	//virtual 문법 : 자식이 만약 나와 완전히 동일한 함수를 구현한다면(override) 자식의 함수를 우선적으로 실행한다.
	virtual int GetAtt() {
		return Att;
	}
private:
	int Att = 10;
};

class Monster :public FightUnit {

};

class Player :public FightUnit {
public:
	int WeaponAtt = 10;
protected:
	// override 붙여서 부모에게 물려받은 함수를 재구현한 함수라는 것을 명시한다. (안 붙여도 의도대로 동작됨)
	int GetAtt() override {
		return FightUnit::GetAtt() + WeaponAtt; // 여기서의 GetAtt()는 내 함수로 인식됨.
	}
};

void Fight(FightUnit* Left, FightUnit* Right) {
	// 겉으로 볼때는 FightUnit지만 동작할 때는 플레이어나 몬스터처럼 동작한다. 그래서 다형성이라고 한다.
	int Value0 = Left->GetAtt();	// 20	
	int Value1 = Right->GetAtt();	// 10

}
int main() {

	Player NewPlayer;
	Monster NewMonster;
	
	Fight(&NewPlayer, &NewMonster);

	return 0;
}

Tip) 클래스 내 멤버변수에서 존재하거나 존재하지 않을 수도 있다면 포인터로 선언하고, 절대로 사라지지 않아야 하면 값형으로 둔다.


과제

오늘은 어제의 TextRpg에 마을을 만든다. (내 코드가 아니라 선생님 코드에서 이어나감)

Weapon 클래스가 생겼다. Player가 무기를 가질 수 있고 이제 랜덤한 기본 공격력에 무기 공격력이 더해져서 계산된다. Town이라는 마을이 생겼고 마을에서 무기 강화와 힐을 할 수 있는 공간이 생겼다.

🪙1. 무기 강화 기능을 구현해라.

선생님 지시
1.
플레이어의 무기의 강화 상태를 보여준다.
기존 그려졌던 랜더링을 전부다 지우고.
1번선택지는 강화
2번선택지는 나간다.
30강에 도달한 무기는 강화가 안 된다고 띄워라.
2.
1강부터 10강까지는 실패해도 강화수치가 떨어지지 않습니다.
10강부터 20강까지는 실패하면 강화수치가 5씩 떨어집니다.
20강부터 30강까지는 실패하면 강화수치가 0이 됩니다.
강화확률 마음대로
(강화 수치 == 강화 레벨)

무기 강화 상태 보여주기

  • Weapon의 Render함수를 만들었다.
// in "Weapon.cpp"

void Weapon::EquipRender() {

	int Size = printf_s("%s ", Name);
	for (int i = 0; i < 50 - Size; i++)
	{
		printf_s("-");
	}

	printf_s("\n");
	printf_s("무기 레벨 %d\n", EquipUp);

	for (int i = 0; i < 50; i++)
	{
		printf_s("-");
	}

	printf_s("\n");
}

강화 기능, 확률

  • Weapon 클래스에 무기 강화 함수 EquipLevelUp()를 만들었다.
  • 확률은 rand()로 난수를 이용해 설정했다.
// in "Weapon.cpp"

void Weapon::SuccessEquipUp(int up) {
	EquipUp += up;
	printf_s("강화에 성공했습니다.\n");
	_getch();
}
void Weapon::FailEquipUp(int down) {
	EquipUp -= down;
	printf_s("강화에 실패했습니다.\n");
	_getch();
}
void Weapon::EquipLevelUp() {
	if (EquipUp < 10) {
		SuccessEquipUp(1);
	}
	else if (EquipUp >= 10 && EquipUp < 20) { // 무기 레벨이 10이상 20미만일 때
		int result = rand() % 10; 
		if (result != 0) { 
			// 강화 성공
			SuccessEquipUp(1);
		}
		else {
			// 강화 실패
			FailEquipUp(5);
		}
	}
	else if (EquipUp >= 20 && EquipUp < 30) {
		int result = rand() % 5; 
		if (result != 0) {
			// 강화 성공
			SuccessEquipUp(1);
		}
		else {
			// 강화 실패
			FailEquipUp(EquipUp);
		}
	}
	SetEquipCost();
}

🪙2. 치료와 골드 기능을 구현해라.

  1. 플레이어가 진짜 치료되게 만들어주세요.
  2. 사냥터의 몬스터가 한 번 죽고 나면 몬스터의 Hp가 다시 차게 만드세요.
  3. 몬스터가 죽었을 때 플레이어가 골드를 얻게 하세요. (기능이 잘 되는지 확인해야하니 즉당히 많이 줘서 테스트)
  4. 강화 1회당 골드를 소모하게 하세요. 돈이 없으면 강화할 수 없다는 메세지가 뜨도록 하세요. 강화 수치마다 강화비용이 증가하게 하세요.

Heal 기능을 FightUnit에 추가

  • MaxHp 개념을 만들었다.
  • 플레이어도 몬스터도 즉, 싸움에 참여하는 객체는 Heal 기능이 필요하기 때문에 FightUnit에 Heal을 넣었다. MaxHp까지 채워주도록 했다. (아래 "FightZone.cpp" 코드 참고)
// in "FightUnit.cpp"

void FightUnit::Heal() {
	Hp = MaxHp;
}
// in "Heal.cpp"

void Town::Heal(Player& _Player)
{
    system("cls");

    while (true) {
        _Player.Heal();
        _Player.StatusRender();
        printf_s("%s가 치료되었습니다.\n", _Player.GetName());

        printf_s("1. 나간다.\n");
        int Select = _getch();

        switch (Select)
        {
        case '1':
            return;
        default:
            break;
        }

        system("cls");

    }

}

플레이어가 몬스터 사냥에 성공하면 골드를 얻도록 하기

  • Player가 FightZone에 In할 때마다 Monster의 Gold를 추가시킨다. 그리고 Player가 이기면 Monster의 골드를 얻을 수 있다.
// in "FightZone.cpp"

void FightZone::In(Player& _Player)
{
	NewMonster.AddGold(9000);
	while (true)
	{
		_Player.StatusRender();
		NewMonster.StatusRender();

		bool IsEnd = false;

		if (_Player.GetRandomSpeed() >= NewMonster.GetRandomSpeed())
		{
			printf_s("플레이어의 선공\n");
			IsEnd = FightLogic(_Player, NewMonster, _Player, NewMonster);
		}
		else 
		{
			printf_s("몬스터의 선공\n");
			IsEnd = FightLogic(NewMonster, _Player, _Player, NewMonster);
		}

			if (true == IsEnd) // 누군가 죽어서 싸움이 끝남.
			{
				NewMonster.Heal();
				if (!_Player.IsDeath()) { // Player가 이긴거라면 골드를 지급.
					int MonsterGold = NewMonster.GetGold();
					printf("%s가 %d의 골드를 얻었습니다.\n", _Player.GetName(), MonsterGold);
					_Player.AddGold(MonsterGold);
					_getch();
				}
				return;
			}
	}

}

강화 비용을 만들고 적용시키기

  • 강화 비용 EquipCost는 강화 레벨에 따라 달라지도록 만들고 싶기 때문에 Weapon 클래스에서 만들고 Get, Set할 수 있도록 했다. (위 in "Weapon.cpp" 코드 참고)
  • 강화 시에 골드가 부족한지 판단하고 강화를 시킨다.
// in "Town.cpp"
  
 void Town::WeaponUp(Player& _Player)
{
    system("cls");

    while (true) {
        _Player.StatusRender();
        //무기 강화 상태 보여주기
        _Player.Weapon.EquipRender();

        if (_Player.Weapon.GetEquipUp() >= 30) {
            printf_s("무기가 최대 레벨입니다.\n");
            printf_s("1. 나간다.\n");

            int Select = _getch();
            switch (Select)
            {
            case '1':
                return;
            default:
                break;
            }

            system("cls");
        }

        printf_s("무기를 강화 하시겠습니까.\n");
        printf_s("1. 강화.\n");
        printf_s("2. 나간다.\n");
        int Select = _getch();

        switch (Select)
        {
        case '1':
            if (_Player.GetGold() >= _Player.Weapon.GetEquipCost()) {
                _Player.SubGold(_Player.Weapon.GetEquipCost());
                _Player.Weapon.EquipLevelUp();
            }
            else {
                system("cls");
                _Player.StatusRender();
                printf_s("골드가 부족합니다.\n");
                printf_s("1. 나간다.\n");

                int Select = _getch();
                switch (Select)
                {
                case '1':
                    return;
                default:
                    break;
                }

                system("cls");
            }
            break;
        case '2':
            return;
        default:
            break;
        }

        system("cls");
}

🪙실행 화면

  • 마을

  • 사냥터에서 플레이어가 사냥에 성공

  • 마을 - 플레이어 치료

  • 마을 - 강화

    • 골드 부족
    • 무기 최대 레벨이라 강화 못하는 모습
profile
일단 시작해보자

0개의 댓글