지난 포스트에서 객체 지향 언어의 4대 기본 원칙 중 갭슐화와 추상화에 대해 알아보았다.
객체 지향 언어의 4대 기본 원칙 :
- 캡슐화 (Encapsulation)
- 추상화 (Abstraction)
- 상속 (Inheritance)
- 다형성 (Polymorphism)
이번 포스트에서는 상속에 대해 알아보려고 한다. 상속은 기본적으로 확장
의 개념이다. 확장이라고 하면 스타크래프트 게임 확장팩 "블루드워"가 나왔을 때가 생각난다(너무 옛날 이야기인가...). 확장팩에는 럭커와 메딕 처럼 새로 추가되는 유닛들이 있었고, 골리앗의 대공 사거리 업그레이드 처럼 기존 유닛의 업데이트도 있었다. 상속은 이렇게 확장이라는 개념을 통해서 코드의 재사용성을 높일 수 있도록 하는 것이다.
class StarcraftUnits {
public Unit marine;
public Unit firebat;
public Unit zerggling;
.
.
.
}
// 확장팩인 BloodWar 는 기존 Starcraft 유닛을 상속받음.
class BloodWarUnits : StarcraftUnits {
public Unit medic;
public Unit lurker;
.
.
.
}
위 예제에서 BloodWarUnit 클래스는 StarcraftUnit 클래스를 상속받음으로써 기존에 이미 있었던 마린, 파이어뱃, 저글링들을 다시 구현하지 않고도 기존 유닛들을 사용할 수 있다.
기존 클래스에 있던 메소드를 자식클래스에서 변경할 수도 있다. 이 때 부모클래스는 변경을 허용하는 메소드 앞에 virtual
또는 abstract
키워드를 가지고 있어야 하고, 자식클래스에서는 override
키워드를 이용하여 부모클래스로부터 가져온 메소드에 변경이 있음을 알려줘야한다.
public class Dog
{
public virtual void Bark()
{
Console.WriteLine("멍멍!");
}
}
public class Puppy : Dog
{
public override void Bark()
{
Console.WriteLine("삑삑!");
}
}
위 예제는 Puppy
클래스가 Dog
클래스를 상속받지만 Bark()
메소드를 그대로 사용하지 않고, 변경하여 사용하는 예이다.
virtual
과 abstract
의 차이는 구현부가 있느냐 없느냐의 차이이다.
virtual
는 부모클래스에 구현부가 있음 : 자식클래스에서 굳이override
하지 않아도 되며, 이때는 부모클래스의 메소드를 그대로 사용할 수 있음.abstract
는 부모클래스에 구현부가 없음 : 자식클래스에서 반드시override
해줘야하고, 부모클래스 이름 앞에abstract
키워드를 붙여서 추상클래스임을 명시해줘야함.
위에서 봤던 강아지 예제를 abstract
를 사용해서 만들어보자.
public abstract class Dog // 클래스 명 앞에 abstract가 붙어있음.
{
public abstract void Bark();
// 구현부가 올 수 없음.
// 구현할 경우 에러 발생.
// {
// Console.WriteLine("멍멍!");
// }
}
public class Puppy : Dog
{
// Bark() 메소드를 반드시 만들어야함.
// 없을 경우 에러 발생.
public override void Bark()
{
Console.WriteLine("삑삑!");
}
}
나는 이런 의문이 들었다.
부모클래스의 변경을 전혀 원치 않을 경우 virtual
이나 abstract
키워드를 사용하지 않고 자식클래스에서 변경하는 방법이 없을까?
방법이 없는 것은 아니다. new
키워드를 사용하여 부모클래스의 메소드를 가릴 수 있지만 아니지만 중요한 문제점을 수반한다. 아래 두가지 예제를 보고 실행결과를 비교해보자.
new
키워드를 이용한 방법:
class Program
{
static void Main(string[] args)
{
Dog myDog = new Puppy();
myDog.Bark();
//실행결과 --> 멍멍!
}
}
public class Dog
{
public void Bark()
{
Console.WriteLine("멍멍!");
}
}
public class Puppy : Dog
{
public new void Bark() // new 키워드를 이용해 부모 메소드를 가린다.
{
Console.WriteLine("삑삑!");
}
}
virtual
키워드를 이용한 방법:
class Program
{
static void Main(string[] args)
{
Dog myDog = new Puppy();
myDog.Bark();
//실행결과 --> 삑삑!
}
}
public class Dog
{
public virtual void Bark()
{
Console.WriteLine("멍멍!");
}
}
public class Puppy : Dog
{
public override void Bark()
{
Console.WriteLine("삑삑!");
}
}
실행 결과가 왜 달라졌을까?
다음 포스트에서 다룰 다형성에서 자세히 들어다보자.
'IT노트 > C#' 카테고리의 다른 글
[C# 하루한개] 디자인 패턴 - 옵저버 패턴 (0) | 2022.01.08 |
---|---|
[C# 하루한개] 디자인 패턴 - 스트래티지 패턴 (0) | 2022.01.07 |
[C# 하루한개] 다형성 (객체 지향 언어의 4대 원칙) (0) | 2022.01.03 |
[C# 하루한개] 추상화 (객체 지향 언어의 4대 원칙) (0) | 2022.01.01 |
[C# 하루한개] 캡슐화 (객체 지향 언어의 4대 원칙) (0) | 2021.12.31 |
[C# 하루한개] 클래스(Class) - 객체 지향 언어의 출발 (0) | 2021.12.30 |