추상화, 상속성, 다형성 개념을 게임을 구현하며 적용해보자
요약
추상화: 사물의 동작과 기능을 추출하여 표현하는 것
상속성: 기본 클래스를 바탕으로 새로운 기능을 추가한 새로운 클래스를 정의하는 것
다형성: 똑같은 호출이라도 상황에 따라, 호출하는 객체에 따라 다른 동작을 할 수 있는 능력
추상화
추상화(Abstraction)
- “표현한다”
- 사물의 동작과 기능을 추출하여 표현하는 것
- 현실의 사물을 객체로 표현하기 위해 => 이 사물이 어떤 특징을 가지며 어떤 동작이 가능한지 데이터 모델링
- 모델링의 결과 필요한 자료와 동작을 선택적으로 작성
- 객체의 효율적이고 안전한 사용을 위해 구현부와 인터페이스를 분리
상속
상속성(Inheritance)
- “재사용한다”
- 기본 클래스를 바탕으로 새로운 기능을 추가한 새로운 클래스를 정의하는 것
- 기본 클래스의 모든 속성과 동작을 물려받으며 필요한 기능을 추가하거나, 필요없는 기능을 변경함
- 기존 객체를 최대한 재활용함으로써 시간과 노력을 절약
- 기본 클래스 == 부모 클래스
- 파생 클래스 == 자식 클래스
다형성
다형성(Polymorphism)
- “상황에 따라 달라진다”
- 똑같은 호출이라도 상황에 따라, 호출하는 객체에 따라 다른 동작을 할 수 있는 능력
- 실제 내부 구현은 다르더라도 개념적으로 동일한 동작을 하는 함수를 하나의 인터페이스로 호출
- 다형성은 동적 바인딩을 하는 가상 함수에 의해 구현됨
적용 실습1 - 플레이어, 몬스터
간단한 게임에서 플레이어, 몬스터를 만드려고 한다.
추상화
- 우리 게임에는 어떤 속성이 필요할까? 체력? 공격력?…
- 필요한 속성과 기능 리스트를 뽑는다.
- 이름, 체력, 공격력, 입력키, 몬스터 등급, 정보출력…
- 지금 생각나는 대부분의 파라미터가 플레이어와 몬스터와 중첩된다.
상속
- 기본 클래스에서 중첩되는 속성을 정의하고, 플레이어나 몬스터 각각의 고유한 특성만 파생 클래스를 추가해 사용하자.
- unit(기본 클래스) - 체력, 공격력, 정보출력…
- player(파생 클래스) - 입력키,…
- monster(파생 클래스) - 몬스터 등급,…
다형성
- 플레이어와 몬스터는 다른 멤버변수를 가지고 있기 때문에, ‘정보출력’이 조금씩 다르다.
- 공통되는 ‘정보출력’은 unit에서 정의하고,
- 차이나는 ‘정보출력’은 player와 monster에서 재정의하자.
#include <iostream>
#include <vector>
using namespace std;
class Unit
{
protected:
string name;
int hp;
int atk;
public:
Unit() = default;
Unit(string _name, int _hp, int _atk) :
name(_name), hp(_hp), atk(_atk) {}
virtual ~Unit() {}
public:
virtual void PrintInfo() // virtual 키워드: 파생 클래스에서 재정의를 예약
{
cout << "name: " << name << '\n';
cout << "hp: " << hp << '\n';
cout << "atk: " << atk << '\n';
}
};
class Player : public Unit // 상속
{
private:
int pressedKey;
public:
Player() = default;
Player(string _name, int _hp, int _atk, int _pressedKey) :
Unit(_name, _hp, _atk), pressedKey(_pressedKey) {}
virtual ~Player() {}
void PrintInfo() override // 가상함수. 재정의되는 함수. override 키워드로 재정의했음을 명시
{
Unit::PrintInfo(); // 기본 클래스 함수 사용
cout << "pressedKey: " << pressedKey << "\n\n";
}
};
class Monster : public Unit // 상속
{
private:
int monsterGrade;
public:
Monster() = default;
Monster(string _name, int _hp, int _atk, int _monsterGrade) :
Unit(_name, _hp, _atk), monsterGrade(_monsterGrade) {}
virtual ~Monster() {}
void PrintInfo() override // 가상함수. 재정의되는 함수. override 키워드로 재정의했음을 명시
{
Unit::PrintInfo(); // 기본 클래스 함수 사용
cout << "monsterGrade: " << monsterGrade << "\n\n";
}
};
int main()
{
Unit* player = new Player("플레이어", 100, 10, 1); // 생성
Unit* monster = new Monster("몬스터", 50, 5, 3);
player->PrintInfo(); // 가상함수 호출
monster->PrintInfo();
delete player; // 메모리 해제
delete monster;
_CrtDumpMemoryLeaks(); // 메모리 누수 체크
}
name: 플레이어
hp: 100
atk: 10
pressedKey: 1
name: 몬스터
hp: 50
atk: 5
monsterGrade: 3
적용 실습2 - 슛골인 게임
간단한 슛 골인 게임을 만들며 최대한 상속과 다형성을 활용해봄
위와 같이 클래스를 나누고 필요한 기능과 동작을 뽑은 뒤 (추상화)
공통된 부분은 기본 클래스로, 차이나는 부분은 파생 클래스로 재정의하여 (상속성)
init, update, render, release 기능을 가상 함수로 구현 (다형성)
※ 틀리거나 개선할 부분이 있다면 알려주세요.
댓글남기기