I'm FanJae.
[20260507] C# ( 추상 클래스 & 인터페이스의 차이점 ) 본문
- C#에서 추상 클래스와 인터페이스는 모두 다형성을 제공할 수 있다.
- 하지만, 목적과 사용 방식에는 차이점이 있다.
1. 추상 클래스
1) 클래스는 하나의 추상 클래스만 상속 받을 수 있다.
- 기본적으로 클래스는 하나의 추상 클래스만 상속 할 수 있다.
- 다중 상속을 허용하지 않는다. (일반 클래스, 추상 클래스 여부를 따지지 않음.)
abstract class Character
{
public abstract void Move();
}
class Player : Character
{
public override void Move()
{
Console.WriteLine("플레이어 이동");
}
}
- 이처럼, Player 는 Character 하나만 상속 받을 수 있다.
2) 추상 클래스는 상태를 저장할 수 있다. (즉, 필드를 가질 수 있다.)
abstract class Character
{
protected int hp = 100;
public abstract void Move();
}
class Player : Character
{
public override void Move()
{
Console.WriteLine("플레이어 이동");
}
}
- 추상 클래스는 상속받는 대상에 공통적으로 들어갈 수 있는 상태. 즉, 필드 값을 가질 수 있다.
- 이 예제에서는 추상 클래스에서 hp 를 공통 상태로 가지는 것이다.
3) 추상 클래스는 구현되어 있는 메서드(일반 메서드)와 추상 메서드를 혼합하여 제공할 수 있다.
abstract class Animal
{
protected string Name { get; set; }
public Animal(string name)
{
this.Name = name;
}
public void Eat()
{
Console.WriteLine($"{Name}이 음식을 맛있게 먹습니다.");
}
// 추상 메서드 본문 선언 금지.
public abstract void MakeSound();
}
- 추상 클래스는 해당 클래스를 상속받을 자식 클래스에게 제공할 공통 기능을 구현하여 제공할 수 있다. (인터페이스도 C# 8.0 버전 이후 부터 디폴트 인터페이스 메서드라는 것이 있는 것 같지만, 권장되지 않는 것으로 보인다.)
4) 추상 클래스는 공통 기반이 되는 메서드를 제공할 수 있다.
abstract class Animal
{
public void Move()
{
Console.WriteLine("이동");
}
}
- 모든 Animal 이 Move() 를 공유한다면 기본 구조 형태로 제공할 수 있다.
5) 추상 클래스를 상속받는 자식 클래스는 추상 클래스에 의존적이다.
abstract class Enemy
{
protected int hp = 100;
public void TakeDamage(int damage)
{
hp -= damage;
}
public abstract void Attack();
}
class Goblin : Enemy
{
public override void Attack()
{
// 공격 관련 구현
}
}
- Goblin 클래스는 Enemy 의 영향을 많이 받게 된다.
- hp 구조를 물려 받고, TakeDamage() 동작을 물려 받는다.
- 또, Attack() 구현을 강제하게 된다.
- 따라서 Enemy() 가 바뀌면, Goblin 도 영향을 받을 수 있다.
※ 즉, Enemy 라는 부모 클래스의 설계에 묶여있고, 강한 결합이라고 한다.
2. 인터페이스
1) 클래스는 여러 개의 인터페이스를 구현할 수 있다.
- C#에서 다중 상속을 허용하지 않지만, 인터페이스는 여러 개 구현할 수 있다.
- 즉, 하나의 클래스가 여러 역할을 동시에 가질 수 있다.
interface IAttackble
{
void Attack();
}
interface IDamageble
{
void TakeDamage(int damage);
}
class Warrior : IAttackble, IDamageble
{
public void Attack()
{
Console.WriteLine("기사가 강력한 공격을 한다")
}
public void TakeDamage(int damage)
{
Console.WriteLine($"법사가 {damage} 만큼 피해를 입었다.");
}
}
- 이처럼 Warrior는 IAttackble, IDamageble 을 동시에 구현할 수 있다.
2) 인터 페이스는 인스턴스 필드를 가질 수 없다.
interface IDamageble
{
// prviate int hp = 100; // 불가능.
void TakeDamage(int damage);
}
- 인터페이스의 핵심은 클래스가 구현해야하는 메서드의 규약을 정의하는 것이다.
- 따라서, hp 와 같은 상태를 직접 저장하지 않는다.
3) 인터페이스는 어떤 동작을 수행해야 하는지 정의만 한다.
interface IAttackble
{
void Attack();
}
- 위처럼 어떤 동작을 수행해야 하는지 정의만 진행하고, 실제 구현은 하지 않는다.
- C# 8.0 버전 이후부터는 구현을 포함 시킬 수 있지만, 권장되지 않는 것 같다.
4) 인터페이스는 역할 정의에 초점을 맞춘다.
interface IMovable
{
void Move();
}
interface IFlyable
{
void Fly();
}
- 인터페이스는 무엇이다보다 무엇을 할 수 있다를 표현하는데 초점을 맞춘다.
5) 인터페이스를 구현하는 클래스는 특정 역할에 의존적이다.
interface IDamageble
{
void TakeDamage(int damage);
}
class Warrior : IDamageble
{
public void TakeDamage(int damage)
{
Console.WriteLine($"법사가 {damage} 만큼 피해를 입었다.");
}
}
- Warrior 는 IDamageble() 이 요구하는 TakeDamage() 를 구현하면 된다.
- 데미지 계산 방식도 클래스 내부에서 자유롭게 정할 수 있다.
- 따라서, 인터페이스를 구현하는 클래스는 특정 역할(IDamageble)에 의존적이나, 내부 구조를 강하게 묶지 않는다.
3. 정리
- 클래스는 여러 추상 클래스를 상속 받는 것은 불가능하지만, 인터페이스는 여러 개 구현할 수 있다.
- 추상 클래스는 상태 값을 저장하는 인스턴스 필드를 가질 수 있지만, 인터페이스는 인스턴스 필드를 가질 수 없다.
- 추상 클래스는 상속 받는 클래스에게 전달할 공통 기능이 구현된 일반 메서드를 구현할 수 있지만, 인터페이스는 기능에 대한 정의만 한다. (C# 8.0 이후 인터페이스도 가능하지만, 권장하는 방식은 아님.)
- 추상 클래스는 상속 받는 클래스와 강하게 결합되어 있다. 즉, 추상 클래스의 상태나 구현 변경시 이를 상속받는 클래스도 영향을 크게 받는다. 반면, 인터페이스는 구현 클래스의 내부 구조를 강제하지 않고, 기능의 정의만 하기 때문에 상대적으로 결합도가 낮다.
'Unity > Unity 초격차캠프' 카테고리의 다른 글
| [20260508] C# (Upcasting, Downcasting, is / as) (1) | 2026.05.08 |
|---|---|
| [20260507] C# ( namespace ) (0) | 2026.05.07 |
| [20260507] C# ( 추상 클래스, 인터페이스 ) (0) | 2026.05.07 |
| [20260506] C# ( 오버로딩 & 오버라이딩 차이점 ) (0) | 2026.05.06 |
| [20260506] C# (캡슐화, 상속, 다형성) (0) | 2026.05.06 |