본문 바로가기

별걸다하는 IT/프로그래밍언어

[C++, java 언어공통]상속을 언제, 왜 쓸까?(inheritance, Is-A)

[C언어, C++언어 완전 정복! 강의 목차 링크]

상황으로 상속 한번에 이해하기

 

자 우리가 메이플스토리 게임을 만들거예요 아주 대강~~~ 으로요

일단 메이플스토리 캐릭터들을 만들어봅시다.

 

음 마법사, 전사, 도적 이렇게 만들어볼게요 그러면 대락적으로

class 마법사 { ~ };
class 전사 { ~ }; 
class 도적 { ~ };

이렇게~? 

근데 캐릭터들은 당연히 움직일 수 있어야 하니까 관련 기능을 넣어줘야 겠죠? 기능을 함수(메소드)로 구현해줍니다.

class 마법사 { 
   void move() { ~긴 코드 ~ }
   void jump() { ~긴 코드 ~} //앗 점프할 수도 있어야 해요 
   void sit() { ~긴 코드 ~ } //앉기 기능도 있네요?
}

이렇게 마법사에게 움직이고 뛰고 앉을 수 있는 기능들을 추가해줬어요.

그런데 이 기능들은 마법사에게만 해당하는 것이 아니죠, 전사도 움직이고 점프하고 앉을 수 있어야 하고, 도적도 움직이고 점프하고 앉을 수 있어야 해요 즉 세 개의 클래스에 똑같이 저 기능을 추가해줘야 하는거예요 벌써부터 노가다 기운이 스물스물 올라오지 않나요..ㅎ

 

지금 예시 캐릭은 3개 뿐이지만 실제로 게임에서는 캐릭터가 엄청나게 많은 종류로 나뉘어져 있어요. 지금 예시로 든 기능 또한 3개 뿐이지만 실질적으로 공통적인 기능은 엄청 많겠죠? 구매도 할 수 있어야 하고 파는 기능도 있어야 하고, 무기 장착 기능도 있어야 하고 등등

 

왼쪽 캡쳐만 봐도 전사 계열만 캐릭터가 벌써 몇개람...!

이렇게 노가다성이 짙으면 의미 없이 시간만 버리고~ 인력만 버리고~ 매우 좋지 않습니다.

 

자 그래도 어찌어찌 10개 나 되는 코드를 다 구현했다고 가정해볼게요

class 마법사 { 걷고 뛰고 앉고 사고 팔고 입고 등등..}

class 전사 { 걷고 뛰고 앉고 사고 팔고 입고 등등..}

class 궁수 { 걷고 뛰고 앉고 사고 팔고 입고 등등..}

class 도적 { 걷고 뛰고 앉고 사고 팔고 입고 등등..}

열심히 구현했는데 나중에 게임을 실행해보니까 걷는 속도가 너무 느리네? 만약에 걷는 속도 기능 부문을 수정해달라고 요청받았어요

 

그러면 하.. 이 많은 클래스 안에 들어 있는 코드를 일일이 다 손봐야 하네요..?

노가다 뒤에 기다리는 헬 노가다...ㅎ 한번 수정하려고 하면 큰일나는거죠.

 

이거를 해결해주는 것이 바로 상속입니다.

자 저렇게 반복적으로 들어가는 캐릭터들이 가지고 있는 공통적인 부문을 빼서 묶는거예요

class character {
   void move() { ~긴 코드 ~ }
   void jump() { ~ 긴 코드 ~} ...등등
}

그리고 옷입혀주듯이! 전사에 character를 입혀버려요! 그러면 전사는 character의 속성을 기본적으로 가지게 되는거죠. 

//java의 경우
class 전사 extends character { ~ }
class 마법사 extends character { ~ }
class 도적 extends character { ~ } 
...등등 여러 직업
//c++의 경우
class 전사 : public character { ~ }
class 마법사 : public character { ~ }
...등등 여러 직업

이렇게 extends 라는 키워드 하나로 자동적으로 속성을 부여할 수 있어요(자바의 경우)

노가다적으로 일일이 기능을 구현해줄 필요가 없는거죠 코드도 쓸데 없이 길어지지 않아요. 깔끔해지죠.

만약 나중에 수정 요청이 들어와도? character class의 걷기 부분만 살짝쿵 수정해주면 끝입니다! 이런걸 보고 수정용이 즉 유지보수가 쉽다라고 표현합니다.

이 때 전사 마법사 도적 이런 클래스가 캐릭터라는 클래스의 특징들을 물려받았다고 해서

전사 마법사 도적 이런 클래스를 자식 클래스라고 부르고 특징을 전해주는 캐릭터 같은 클래스를 부모 클래스라고 부릅니다.

또 공통적으로 가지고 있는 즉 기본이 된다고 해서 부모 클래스를 base class, 자식 클래스파생 클래스라고 부르기도 합니다.

자식 클래스는 부모클래스로부터 공통적 속성을 받고 추가적으로 자신만의 속성을 구현할 수 있어요.

class 전사 : public character {
    void 근접공격() { } //전사만의 속성 
    //코드적으로는 보이진 않지만 character의 기능을 가지고 있습니다.
}

친구에게 얘기하듯이 상속에 대해서 쉽게 풀어쓰려고 했는데 도움이 되셨나요?

잠깐 쉬는 타임으로 중간광고 하나 헤헤. 동기부여는 발전의 거름이다!!

 

 

 

 

 

 

상속을 쓰는 이유~

나~~중에 빼먹은 공통적인 기능이 생각나서 추가해주려고 한다? 부모클래스에다가 기능하나만 더 추가해주면 돼요

일일이 모든 직업 클래스들에게 다시 노가다 뛰지 않아도 됩니다. 이것을 확장성이 용이하다고 해요.

나중에 다른 게임을 구현할 때도 이 character클래스를 빼다가 활용할 수 있겠죠? 이렇게 각각의 클래스에다가 구현하는게 아니라 공통 클래스를 빼서 분리시켜놓음으로써 붙였다 뗐다 하듯이 쓸 수 있으니 이것을 재사용이 가능하다라고 말하기도 해요.

 

즉 상속을 쓰면

1. 유지보수가 쉬워지고

2. 확장성이 용이해지고

3. 모듈화를 통해 재사용이 가능해지며

4. 코드가 간결해집니다.

5. 이로써 개발시간을 단축할 수 있어요.

 

 

상속일 경우, 각각의 데이터 크기와 메모리의 구성도는?

 

그럼 자식 클래스는 부모 클래스의 속성을 다 물려받았으니 더 많은 데이터를 가지고 있을 것이고 그럼 차지하는 메모리 크기가 크겠네요? --> 보통 그렇습니다

Student 클래스와 Person 클래스가 있다고 가정해볼게요. Student도 사람이니 분명 사람의 기능을 Student가 물려받아야 하겠죠? (이렇게 '사람 = 학생, 직장인', '무기 = 창, 활' 처럼 이런관계에 있는 것을 Is-A 관계라고 하고 상속은 이를 표현하는 데 사용합니다.)

class Student : public Person {
   Student 멤버변수와 멤버함수 (특징과 기능들)..
}

이럴 경우 Student는 Person을 상속받아 확장한 클래스이므로, 바이트 단위로 따져 보면 보통 Student가 Person보다 더 큽니다.

이 때 이 주소값은 Student 객체의 원래 주소값과 같을 수도 있고, 조금 더 클 수도 있습니다.

대개의 경우 이런 과정은 우리가 상속 키워드로 상속시킬 시 컴파일러가 자연스럽게 처리해 주므로 프로그래머가 체감할 수는 없습니다~

 

 

상속 표시 방법?

상속은 보통 화살표로 자식과 부모 관계를 표현합니다.

이 그림에서는 드래곤 트롤 등등의 자식 클래스가 Monster 라는 부모클래스로부터 특징과 기능을 물려받았다고 화살표로 표시하고 있네요!

 

참고로 상속은 한 번만 가능한게 아니라 여러 하위 단계를 가질 수 있어요 나누기 나름!

예시 ↓

class 사람

class 직원 extends 사람

class 정직원 extends 직원

class 계약직 extends 직원

class 알바 extends 계약직

 

IS -A , Has- A?

어떤 것을 상속으로 표현하는 것이 좋을까? 상속은 흔히 IS-A관계라고 해요.

IS-A관계이면 상속으로 구현하는 것이 좋습니다. IS-A가 그럼 뭘까요~

이미 많은 예시를 통해 유추했겠지만 IS-A는 부모 자식관계처럼 똑같은 것을 말해요. Is가 '~이다'라는 거니까요.

 

창은 무기이고, 활도 무기이고, 몽둥이도 무기이고 이렇게 부모 자식 관계이면서 equal 관계인 것을 IS-A관계라고 합니다.

위의 예시도, 계약직도 직원이고 정직원도 직원이고!

토끼는 동물이고, 강아지도 동물이고, 호랑이도 동물이고! 등등~

이렇게 모든 토끼는 동물이다. 모든 학생은 사람이다 이렇게 표현할 수 있으면 IS-A관계에 있다고 말합니다.

class rabbit : public animal {}
class dog : public animal {}
class tiger : public animal {}

이와 대조되는 개념으로 HAS-A가 있어요

has 말그대로 가지다 소유의 개념입니다. 자동차는 바퀴를 가지고 있어요 , 강아지는 꼬리를 가지고 있어요 이런 관계가 HAS-A입니다. HAS-A관계를 실수로 상속으로 구현하려는 사람이 있는데 권장되지 않습니다

HAS-A는 말그대로 내포관계라서 아래처럼 클래스 내부에 구현해줍니다.

class Car 
{
    Wheel* wheel[4]; //자바일 경우 포인터 없음!
    Break* break; //자바일 경우 포인터 없음!
    
    Window window[4];
    Handle handle;
}

이번 포스팅은 여기까지!

도움이 됐다면 공감 OR 댓글 OR 광고보답 좋아용