상속이 뭐야? 🧐

상속은 확장의 개념이다. 추상클래스, 일반클래스 모두 상속을 통해 특정 객체의 개념을 확장시킬 수 있다.(인터페이스의 경우 기능확장이라는 말이 좀 더 어울리는 것 같다.) 인터페이스와 추상클래스는 이전 포스트에서 다루었으니 일반클래스를 예시로 들겠다.

💚 예시

오크라는 객체가 있다고 하자. 이 오크라는 객체는 마법사 오크가 될수도, 전사 오크, 궁수 오크 등이 될 수 있다. 이런 오크들을 구현할 때 상속을 사용한다. 직업이 있는 오크 모두 하나의 오크라는 객체를 상속받을 수 있는 것이다. 일반클래스의 상속은 추상클래스나 인터페이스를 상속받는 것과 다르게 부모클래스도 인스턴스할 수 있다. 즉, 아무렂 직업이 없는 일반 오크(부모클래스)도 존재할 수 있고, 이 오크를 기반으로 다양한 직업을 가진 오크(자식클래스)도 존재할 수 있다.

🍑 위의 내용을 바탕으로 코드를 만들어 보자!

🍑 일반클래스, 추상클래스, 인터페이스 모두 활용해보자!

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
public abstract class Monster //몬스터라는 분류!
{
    private int maxHp;
    private int maxMp;
    private int hp;
    private int mp;
    private bool isAbleSkill;
    public bool IsAbleSkill
    {
        get => mp > 0;
        private set => isAbleSkill = value;
    }
    private bool IsAlive=> hp > 0;
    public int Hp
    {
        get => hp;
        set
        {
            var _hp = hp + value;
            if (_hp > maxHp)
            {
                hp = maxHp;
            }
            else if (_hp <= 0)
            {
                Die();
            }
            else
            {
                hp = _hp;
            }
        }
    }
    public int Mp
    {
        get => mp;
        set
        {
            var _mp = mp + value;
            if (_mp > maxMp)
            {
                mp = maxMp;
            }
            else if (_mp <= 0)
            {
                mp = 0;
            }
            else
            {
                mp = _mp;
            }
        }
    }
    protected Monster(int maxHp, int maxMp)//abstract 클래스의 생성자는 항상 protected로!
    {
        this.maxHp = maxHp;
        this.maxMp = maxMp;
        hp = maxHp;
        mp = maxMp;
    }
    public abstract void UseSkill();
    public abstract void Die();
    public void SetEnableUseSkill(bool able)
    {
        isAbleSkill = able;
    }
}
public class Orc : Monster
{
    public override void UseSkill()
    {
        if (IsAbleSkill)
        {
            Skill();
        }
    }
    public Orc(int maxHp, int maxMp) : base(maxHp,maxMp)
    {
    }
    protected virtual void Skill()
    {
        Console.WriteLine("일반오크 스킬 발동!");
    }
    public override void Die()
    {
        Console.WriteLine("오크 죽음!");
    }
}
public class WizardOrc : Orc, IFly
{
    public WizardOrc(int maxHp, int maxMp) : base(maxHp,maxMp)
    {
    }
    protected override void Skill() //부모의 함수를 오버라이딩 하여 자신에게 알맞은 함수를 실행함
    {
        Console.WriteLine("마법사 오크 스킬 발동!");
    }
    public void Fly()
    {
        Console.WriteLine("휘익~ 마법사 오크 난다!");
    }
}
public class KnightOrc : Orc
{
    public KnightOrc(int maxHp, int maxMp) : base(maxHp,maxMp)
    {
    }
    protected override void Skill()
    {
        Console.WriteLine("전사오크 스킬 발동!");
    }
}
public class ArcherOrc : Orc
{
    public ArcherOrc(int maxHp, int maxMp) : base(maxHp,maxMp)
    {
    }
    protected override void Skill()
    {
        Console.WriteLine("궁수오크 스킬 발동!");
    }
}

상속의 특징은? 🧐

  • 자식클래스가 부모클래스의 필드와 메소드를 모두 가지고 있다.
  • 부모클래스에서 private으로 선언되어있는 요소들은 자식클래스라도 접근이 불가능하다.(가지고는 있음!)
  • 부모클래스에서 protected로 선언되어있는 요소는 자식클래스만 접근이 가능하다.
  • 부모클래스이 메소드를 virtual/override 를 통해 자식클래스에서 재정의 할 수 있다.
  • interface를 제외한 모든 상속은 다중상속이 불가능하다.