상세 컨텐츠

본문 제목

#16. 추상 클래스(Abstract Class)

유니티 학습/세미나 자료

by 남민우_ 2024. 8. 5. 16:52

본문

1.  추상클래스란?

내부 구현은 이루어지지만 자기 자신을 인스턴스화 하지 않는다.

일반 클래스 ~ 인터페이스의 중간 단계라고 생각하면 이해가 편하다.

 

이러한 추상 클래스를 이해하기 위해, 몬스터의 공격 작동을 구현하면서 진행해보자.

2. 실습 : 몬스터 공격 구현

코드 추가

public class BaseMonster : MonoBehaviour
{
    public float damage = 100f;

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            Attack();
        }
    }
    public virtual void Attack(); //<- 에러!
}

 

이때 Attack() 함수는 몬스터가 동일하게 가지고 있어야 하지만, 그 기능은 몬스터마다 달라야 한다.

= 내부 구현을 하지 않아야 한다.

하지만 virtual 을 사용하는 순간 내부 구현이 강제된다.

 

이처럼 어느 정도의 내부 구현은 필요하지만, 일부에서는 선언만 필요로 할 때

추상 클래스를 사용한다.

 

3. 추상 클래스

기본 내부 구현을 이루어 놓은 상태에서 자식 클래스가 덮어 씌울 수 있게

 : 클래스/함수 앞에 'abstract' 키워드를 붙여서 사용한다.

 

Abstract

'추상적인' 이라는 뜻을 가지고 있다.

자체적으로 내부 구현( 위 코드에서의 Update() ) 를 만들 수도, 선언만 ( 위 코드에서의 Attack() ) 만들어 놓을 수도 있다.

선언만 만들어 놓을 수 있기에 인스턴스화는 불가능하지만,

내부 구현을 만들어 놓을 수도 있어 자식클래스에서 상속받아 사용하게 할 수도 있다.

 

코드 추가

//BaseMonster 클래스 앞에, Attack() 함수의 virual 을 abstract로 변경
public abstract class BaseMonster : MonoBehaviour
{
    public float damage = 100f;

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            Attack();
        }
    }
    public abstract void Attack(); 
}
----------------------------------------
//새로운 스크립트
public class Goblin : BaseMonster
{
	public override void Attack()
	{
		Debug.Log("고블린 공격 : " + damage);
	}
}

 

에디터 설정

객체를 하나 만들고 'Goblin' 으로 이름지었다

위 코드로 만든 Goblin 스크립트를 컴포넌트로 할당

 

실행 결과

디버그 로그 정상 출력 모습

정상적으로 동작한다

이때 damage 수치 100은 BaseMonster에게서 상속받은 수치이다.

더보기

Q. 실제 플레이를 하게 되면 몬스터마다 damage 수치가 달라야 할텐데, 

BaseMonster에서 상속받으면 이 수치가 고정되는게 아닌가?

 

A. damage 변수는 public 선언이기 때문에 Inspector 창에서 바꿀 수 있다.

 

그럼 다른 몬스터도 추가해보자.

이번에는 고블린에 이어 오크 몬스터를 만들어보려고 한다.

 

코드 추가

public class Oak : BaseMonster
{
	public override void Attack()
	{
		Debug.Log("오크 공격 : " + damage);
	}
}

 

에디터 설정은 기존 고블린과 동일한 작업을 수행한다.

 

오크와 고블린 디버그 로그 출력

마찬가지로 정상적으로 작동한다.

 

이때 고블린과 오크는 같은 부모, BaseMonster를 상속받았다.

여기서, 지난 파트에서 배운 점을 활용할 수 있다.

바로 '다형성' 말이다.

BaseMonster 클래스로 두 객체를 한번에 관리할 수 있다.

 

코드 추가

public class Test : MonoBehaviour
{
	public BaseMonster[] monsters;

	private void Start()
	{
		for(int i = 0; i< monsters.Length; i++) 
		{
			Debug.Log(monsters[i].gameObject.name);
		}
	}
}

 

에디터 설정

빈 게임 오브젝트 - Test 스크립트 할당 - Monsters 배열 추가 - 객체 할당

 

실행 결과

정상적으로 출력되는 모습을 볼 수 있다.

 

이 과정처럼 같은 부모를 상속받는 객체들은 부모가 일반 클래스인지, 추상 클래스인지 상관없이 부모 클래스의 배열을 통해 한번에 관리할 수 있다.

 : 다형성 특징 활용

 

하지만 여기서 BaseMonster 스크립트를 컴포넌트로 추가하려고 하면?

에디터에 에러창이 나타난다

스크립트 추가가 불가능하다.

위에서 언급한 Abstract 추상 클래스는 인스턴스화가 불가능하다 라는 특징 때문이다.

 

4. 정리

추상 클래스

1. 내부 구현을 이루어놓을 수도, 선언만 사용할 수도 있는 클래스

2. 자기 자신은 인스턴스화가 불가능하다.

3. 클래스와 함수 앞에 'abstract' 키워드를 사용한다.

4. 자신을 상속받는 자식 클래스에 다형성의 특징을 활용할 수 있다.

'유니티 학습 > 세미나 자료' 카테고리의 다른 글

#17. 프로퍼티(Property)  (0) 2024.08.05
#15. 인터페이스(Interface)  (0) 2024.08.05
#14. 오버라이드(Override)  (0) 2024.08.03
#13. 다형성  (0) 2024.08.03
#12. 상속 심화  (0) 2024.08.02

관련글 더보기