본문 바로가기

C#

C# 문법 _ 추상클래스, 인터페이스, abstract, virtual

C# 인터페이스와 추상클래스의 차이점

  Interface Abstract Class
접근 지정자 - 함수에 대한 접근 지정자를 가질수 없습니다.
- public 만 사용가능
- 함수에 대한 접근 지정자를 가질 수 있습니다. 
구현 구현이 아닌 선언만 가짐 구현도 가질 수 있음
속도 상대적으로 느림 빠름
인스턴스화 불가 불가
필드 상수만 가능, 프로퍼티 선언 가능 정의할 수 있음, 프로퍼티 선언,
구현 가능(자동구현되긴함)
메소드 추상메소드만 가짐(즉, 다 구현해야함) 비추상 메소드도 가질 수 있음
상속 하나 이상 가능 하나만 됨
생성자 선언 불가 선언 가능
역할 다양한 클래스에서 동일한 메소드명을 공유,
클래스 간 일관성 있는 동작을 보장하기 위한 계약 역할
동일한 종류의 클래스들이 공유하는 기본 구현을 제공
사용 경우 다양한 클래스들이 특정 메소드나 동작을 구현하도록 강제하려는 경우 다양한 클래스들이 공통된능이나 동작을 가지고 있고,
이러한 기능을 기본적으로 구현하면서도 하위 클래스에서 확장 및 수정이 필요한 경우

abstract 메소드가 있으면 클래스도 abstract 키워드 달아줘야함

abstract클래스에서 프로퍼티는 아래와 같이 선언까지만 가능. 구현은 상속받은 자식 클래스에서 가능

c#에서 프로퍼티는 메소드로 구현됨

public abstract class Parent : MonoBehaviour
{
    public abstract int TestProperty
    {
        // Notice the accessor accessibility level.
        protected set;

        // No access modifier is used here.
        get;
    }
}
public class child : Parent
{
    public override int TestProperty 
    {   get => throw new System.NotImplementedException();
        protected set => throw new System.NotImplementedException(); 
    }
}

 

- virtual : 하나의 기능을 하는 완전한 클래스이며, 파생클래스에서 상속해서 추가적인 기능추가 및 virtual 한정자가 달린 것을 재정의해서 사용 가능. 재정의 필수X

- abstract : 여러 개의 파생클래스에서 공유할 기본클래스의 공통적인 정의만 하고, 파생클래스에서 abstract한정자가 달린 모든 것을 재정의해야함. 재정의 필수O

- interface : abstract와 비슷하나 멤버변수를 사용할 수 없음. static 상수는 가능. 

 

abstract는 주로 계층적인 상속( Dog : Animal ,,, Cat : Animal)구조에서 사용되며

interface는 주로 서로 다른 계층 ( Speaker : ISpeak ,,, Npc : ISpeak기능을 추가하려고 할 때 사용.

 

 프로퍼티 관련

  • abstract: Never an auto-property but looks like an auto-property.
  • virtual: Can be an auto-property.
  • override: Can be an auto-property.

 

< interface 사용 이유 중 하나 >

플레이어가 논타겟으로 공격했을 때 범위 안의 모든 공격 가능한 오브젝트에게 피해를 준다고 하자. 이 경우 대부분 몬스터가 해당하겠지만, 공격 가능한 오브젝트 등도 해당될 수 있다. 이때 간단하게는 다음과 같이 코드를 작성할 수 있다.

private void OnCollisionEnter(Collision collision)
 {
     if (CompareTag("Attackable"))
     {
         collision.gameObject.GetComponent<Status>().hp -= damage;
     }
 }

하지만, Tag를 위와 같이 너무 큰 범위로 묶는 것은 효율적이지 못하다. 그렇다고 태그별로 조건문을 일일이 달아줄 수도 없는 노릇이다. 이럴 때 인터페이스를 활용하면 다음과 같이 코드를 바꿀 수 있다.

private void OnCollisionEnter(Collision collision)
 {
     Attackable attackable = collision.gameObject.GetComponent<Attackable>();
     if (attackable != null)
     {
         attackable.Damaged();
     }
 }

인터페이스를 상속하면 컴포넌트로써 읽는 것이 가능해지고, 다중 상속이 가능한 덕분에 어떤 클래스에라도 Attackable 인터페이스를 상속하여 공격 가능한 오브젝트임을 표현할 수 있다.