러닝센터 9강 - 상속 - 다운캐스팅 - 업 캐스팅

자식객체를 부모 타입에 집어넣는 행위 업캐스팅

과제 : 상속 구조를 그림으로 표현하여 코드로 옮겨본다.



======[ 다운캐스팅 ]=======================================================


#include <iostream>
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <string>

using namespace std;

// 중복코드를 가지고 만든 캐릭터 클래스
class Character {
protected:
 // 중복 속성들
 string _name;
 int _hp;
 int _damage;
public:
 Character(string name, int damage) {
  _name = name;
  _hp = 100;
  _damage = damage;
 }

 // 중복 메소드들
 void Move() {
  cout << "[" << _name << "] 님이 이동을 합니다. " << endl;
 }
 void Hit(int damage) {
  cout << "[" << _name << "] 님이 " << damage << " 데미지를 입었습니다. " << endl;
 }
 void Die() {
  cout << "[" << _name << "] 님이 사망했습니다. " << endl;
 }

 void Attack() {
  cout << "[" << _name << "] 님이 " << _damage << "만큼의 공격을 합니다. " << endl;
 }
};

// 플레이어는 캐릭터를 상속함
class Player : public Character
{
private:
 int _level;
 int _gravity;
 string _talkMessage;
public:
 Player(string name, string talkMessage, int damage)
  // 플레이어의 생성자를 호출하기전에 캐릭터의 생성자를 호출함
  : Character(name, damage) {

  _talkMessage = talkMessage;
  _level = 1;
  _gravity = 1;

  cout << "[" << _name << "] 님이 접속하였습니다." << endl;
  Talk();
 }

 ~Player() {}

 void Talk() {
  cout << "[" << _name << "] 메시지 : "
   << _talkMessage << endl;
 }
 
 void Jump() {
  cout << "[" << _name << "] 님이 점프를했습니다. " << endl;
 }
};

class Monster : public Character
{
private:
 int _skillType;
public:
 Monster(string name, int skillType, int damage)
  : Character(name, damage) {

  _skillType = skillType;

  cout << "[" << _name << "] 님이 나타났습니다." << endl;
 }
 ~Monster() {}

 void Skill()
 {
  cout << "[" << _name << "] 님이 " << _skillType << "타입의 스킬을 사용합니다. " << endl;
 }

};

class Creature : public Character
{
private:
 int _time;
public:
 Creature(string name, int time, int damage)
  : Character(name, damage) {

  _time = time;

  cout << "[" << _name << "] 님이 소환 됐습니다." << endl;
  Timer();
 }
 ~Creature() {}

 void Timer()
 {
  cout << "[" << _name << "] 님이 " << _time << " 시간뒤에 소멸됩니다." << endl;
 }
};

//전투 스테이지로 각 캐릭터들은 이동, 타격 사망을 할 수 있다.

class WarStage{

public:
 /*
 void MoveTarget(Player* player){
  player->Move();
 }
 void MoveTarget(Monster* monster){
  monster->Move();
 }
 void MoveTarget(Creature* creature){
  creature->Move();
 }
 */
 // 서로관의 관계를 단순화
 void MoveTarget(Character* character){
  character->Move();
 }
};


//캐릭터들을 이동 시킴
//캐릭터들을 배열로 받아 반복문을 통해 Move 메소드를 실행한다.
void MoveAll(Character** characters){
 for (int i = 0; i < 3; i++)
 {
  characters[i]->Move();
 }
}


void main()
{
 // 메모리 주소를 할당 NEW
 Player* player = new Player("홍길동", "안녕", 100);
 Monster* monster = new Monster("몬스터", 1, 100);
 Creature* creature = new Creature("크리쳐", 10, 100);
 
 WarStage* warStage = new WarStage();
 /*
 warStage->MoveTarget(player);
 warStage->MoveTarget(monster);
 warStage->MoveTarget(creature);
 */

 // 메모리 주소로 접근
 // 객체형 배열 생성
 // 캐릭터 객체 배열에 자식 객체 대입
 Character* characters[3];
 characters[0] = player; // 업캐스팅(player* -> Character);
 characters[1] = monster;// 업캐스팅(monster* -> Character);
 characters[2] = creature;// 업캐스팅(creature* -> Character);

 MoveAll(characters);
 
 delete warStage;
 delete player;
 delete monster;
 delete creature;

 /*
 // 캐스팅은 주소를 가지고 있으므로 매모리 주소로 접근 해야만 된다. (포인터)
 // 업캐스팅은 상속 에서만 가능합
 // 업캐스팅 
 Character* c = new Player("홍길동", "안냥", 100);
 // 다운캐스팅 캐릭터 타입의 주소를 플레이어 타입의 주소로 변경 대입 자식의 타입으로 바꾸는것.
 //플레이어 포인터 객체 p에 플레이어 주소를 대입한다.
 Player* p = (Player*)c;
 p->Jump();
 
 delete p;
 
 // 업캐스팅 ( 그리쳐객체의 주소를 캐릭터 포인터 변수에 대입)
 Character* c = new Creature("멀록", 10, 100);
 //c ->Timer() 에러발생
 
 //다운캐스팅 ( 캐릭터 타입의 주소를 크리쳐 타입의 주소로 변경 대입
 Creature* cr = (Creature*)c;
 cr->Timer();

 delete cr;
 //c = new Car;
 */
}

====[ 가상함수 ]============================================================
// 부모 클래스형 배열을 만든다.
// 배열에 각 객체 변수를 대입한다.

// 배열 객체를 받아 반복문을 사용하여 각 객체의Move 메소드를 실행한다.


// 자료구조. 

// 가상함수 - 진짜가 아닐수도 있다. 오버라이드 함수가 있을때 부모 클래스의 함수가 블라인드 된다.

virtual void Move() {
  cout << "[" << _name << "] 님이 이동을 합니다. " << endl;
 }
// 상속 구조에서 부모 클래스의 메소드를 오버라이드 할때 자식 클래스에서 재정의 하고 부모 클래스에서
메소드 명 앞에 virtual 을 붙여준다.

오버라이드 강제화. - 순수 가상 함수

 // 모든 캐릭터 들이 Attack을 새로 만들어야 할 경우
 // 부모 클래스의 Attack의 정의는 의미 없어짐.
 // 가상함수는 자식 클래스의 재정의 ( 오버라이드) 에 대한 강제성이 없지만
 // 순수 가상함수는 자식 클래스의 재정의( 오버라이드 )를 강제화함
 // 하나 이상의 순수 가상 함수를 가진 클래스는 추상 클래스가 된다.
 // 생성 할 경우 오류가 난다. 추상 클래스는 생성 할 수 없다.
 
virtual void Attack() = 0; // 부모 클래스에서 접근 하기 위해 순수 가상함수가 필요함.

http://www.unity2d.kr/index.php?mid=cpp_csharp_study&page=2&document_srl=302




======================================================================

#include <iostream>
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <string>

using namespace std;

// 중복코드를 가지고 만든 캐릭터 클래스
class Character {
protected:
 // 중복 속성들
 string _name;
 int _hp;
 int _damage;
public:
 Character(string name, int damage) {
  _name = name;
  _hp = 100;
  _damage = damage;
 }

 // 중복 메소드들
 // 가상 함수
 virtual void Move() {
  cout << "[" << _name << "] 님이 이동을 합니다. " << endl;
 }
 void Hit(int damage) {
  cout << "[" << _name << "] 님이 " << damage << " 데미지를 입었습니다. " << endl;
 }
 void Die() {
  cout << "[" << _name << "] 님이 사망했습니다. " << endl;
 }
 
 // 모든 캐릭터 들이 Attack을 새로 만들어야 할 경우
 // 부모 클래스의 Attack의 정의는 의미 없어짐.
 // 가상함수는 자식 클래스의 재정의 ( 오버라이드) 에 대한 강제성이 없지만
 // 순수 가상함수는 자식 클래스의 재정의( 오버라이드 )를 강제화함
 // 하나 이상의 순수 가상 함수를 가진 클래스는 추상 클래스가 된다.
 // 생성 할 경우 오류가 난다. 추상 클래스는 생성 할 수 없다.

 virtual void Attack() = 0;
};

// 플레이어는 캐릭터를 상속함
class Player : public Character
{
private:
 int _level;
 int _gravity;
 string _talkMessage;
public:
 Player(string name, string talkMessage, int damage)
  // 플레이어의 생성자를 호출하기전에 캐릭터의 생성자를 호출함
  : Character(name, damage) {

  _talkMessage = talkMessage;
  _level = 1;
  _gravity = 1;

  cout << "[" << _name << "] 님이 접속하였습니다." << endl;
  Talk();
 }

 ~Player() {}

 void Talk() {
  cout << "[" << _name << "] 메시지 : "
   << _talkMessage << endl;
 }

 void Jump() {
  cout << "[" << _name << "] 님이 점프를했습니다. " << endl;
 }

 void Attack() {
  cout << "[" << _name << "] 님이 " << _damage << " 칼을 휘두르면서 공격을 합니다. " << endl;
 }
};

class Monster : public Character
{
private:
 int _skillType;
public:
 Monster(string name, int skillType, int damage)
  : Character(name, damage) {

  _skillType = skillType;

  cout << "[" << _name << "] 님이 나타났습니다." << endl;
 }
 ~Monster() {}

 void Skill()
 {
  cout << "[" << _name << "] 님이 " << _skillType << "타입의 스킬을 사용합니다. " << endl;
 }

 // 오버라이드
 void Attack() {
  cout << "[" << _name << "] 님이 " << _skillType << " 을 사용 하면서 공격을 합니다. " << endl;
 }

};

class Creature : public Character
{
private:
 int _time;
public:
 Creature(string name, int time, int damage)
  : Character(name, damage) {

  _time = time;

  cout << "[" << _name << "] 님이 소환 됐습니다." << endl;
  Timer();
 }
 ~Creature() {}

 void Timer()
 {
  cout << "[" << _name << "] 님이 " << _time << " 시간뒤에 소멸됩니다." << endl;
 }
 // 가상 함수 선언
 void Move() {
  cout << "[" << _name << "] 팔짝 팔짝 뛰면서 님이 이동을 합니다. " << endl;
 }
 void Attack() {
  cout << "[" << _name << "] 님이 하면서 공격을 합니다. " << endl;
 }

};

//전투 스테이지로 각 캐릭터들은 이동, 타격 사망을 할 수 있다.

class WarStage{
public:

 // 서로관의 관계를 단순화
 void MoveTarget(Character* character){
  character->Move();
 }
};


//캐릭터들을 이동 시킴
//캐릭터들을 배열로 받아 반복문을 통해 Move 메소드를 실행한다.


void ActionAll(Character** characters){
 for (int i = 0; i < 3; i++)
 {
  characters[i]->Move();
  characters[i]->Attack();

 }
}

void main()
{

 //객체타입 변수 생성 / 생성자 호출 / 맴버변수 초기화
 Player* player = new Player("오징어", "맛있엉", 1);
 Monster* monster = new Monster("꼴뚜기", 1, 1);
 Creature* creature = new Creature("갑오징어", 2, 1);

 //객체 배열 생성 후 객체 변수 대입
 Character* characters[3];
 characters[0] = player;
 characters[1] = monster;
 characters[2] = creature;

 // Mmove 함수 호출
 ActionAll(characters);


 for (int i = 0; i < 3; i++)
 {
  delete characters[i];
 }


}



=====[UNITY 슈팅게임]=======================================================




댓글

이 블로그의 인기 게시물

날짜 시간 시간차 시간 계산 하기

코루틴에서 CallBack 함수 적용하기

C++ 언어 퍼센트 구하는 방법 / 기본 언어 퍼센트 구하는 방법