[로봇활용_10주차] C# 추상 클래스(Abstract Class)

최윤호·2025년 10월 11일
post-thumbnail

추상 클래스: 미완성 설계도

"일부는 내가 미리 만들어주고, 핵심 기능만 각자 만들게 할 순 없을까?"

이럴 때 사용하는 것이 바로 추상 클래스(Abstract Class)입니다.
마치 일부는 완성되어 있고, 일부는 비어있는 '미완성 설계도'와 같습니다.
이번 글에서는 이 미완성 설계도, 추상 클래스가 무엇인지 파헤쳐 보겠습니다!

1)추상 클래스란?

이름 그대로 '추상적'인 클래스입니다. 즉, 그 자체로는 완전한 객체를 만들 수 없고,
다른 클래스가 상속하여 비어있는 부분을 완성해야만 의미를 갖는 클래스입니다.

비유: 도형 그리기
'도형'이라는 개념을 생각해 봅시다. 우리는 '도형' 그 자체를 그릴 수 없습니다.
'원', '사각형', '삼각형' 등 구체적인 도형을 그릴 수 있죠.
여기서 '도형'이 추상 클래스(Abstract Class)에 해당하고, '원', '사각형'
추상 클래스를 상속받은 구체적인(Concrete) 클래스가 됩니다.

2)추상 클래스의 주요 특징

1. abstract키워드를 사용하여 클래스를 선언합니다.
2. 인터페이스처럼, 그 자체로 객체를 생성할 수 없습니다. (new Shape() -> 불가능!)
3. 일반 메서드(구현 완료)와 추상 메서드(껍데기만)를 모두 가질 수 있습니다.
(이것이 인터페이스와의 가장 큰 차이점!)
4. abstract로 선언된 추상 메서드는 자식 클래스에서
반드시 override키워드를 사용해 재정의(구현)해야 합니다.
5. 단 하나의 추상 클래스만 상속받을 수 있습니다. (단일 상속 원칙)

3)추상 클래스 사용법

'도형' 만들기 예제를 코드로 직접 만들어보며 이해해 봅시다.
모든 도형은 '색상'을 가지고 있고, '그리는' 기능이 필요하다고 가정해 보겠습니다.

1단계: 추상 클래스 정의

Shape클래스는 Describe()라는 완성된 메서드와,
Draw()라는 미완성된 추상 메서드를 모두 가지고 있습니다.

[코드]

// "이 클래스는 미완성이야!" 라고 abstract 키워드로 선언
public abstract class Shape
{
    public string Color { get; set; }

    // 1. 일반 메서드: 모든 도형이 공통으로 사용할 수 있는 완성된 기능
    public void Describe()
    {
        Console.WriteLine($"이 도형의 색상은 {Color}입니다.");
    }

    // 2. 추상 메서드: 껍데기만 있음. "나를 상속받는 놈은 Draw를 반드시 구현해야 해!"
    public abstract void Draw();
}

2단계: 상속 및 구현하기

이제 Shape라는 미완성 설계도를 바탕으로
구체적인 '원''사각형' 클래스를 만들어 보겠습니다.

[코드]

// 1. 원 클래스
public class Circle : Shape
{
    // Shape 추상 클래스와의 약속을 지키기 위해 Draw() 메서드를 반드시 구현(override)
    public override void Draw()
    {
        Console.WriteLine("원을 그립니다. ●");
    }
}

// 2. 사각형 클래스
public class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("사각형을 그립니다. ■");
    }
}

3단계: 추상 클래스 사용

추상 클래스도 인터페이스처럼 다형성을 활용하여 코드를 유연하게 만들 수 있습니다.

[전체 코드]

using System;

// "이 클래스는 미완성이야!" 라고 abstract 키워드로 선언
public abstract class Shape
{
    public string Color { get; set; }

    // 1. 일반 메서드: 모든 도형이 공통으로 사용할 수 있는 완성된 기능
    public void Describe()
    {
        Console.WriteLine($"이 도형의 색상은 {Color}입니다.");
    }

    // 2. 추상 메서드: 껍데기만 있음. "나를 상속받는 놈은 Draw를 반드시 구현해야 해!"
    public abstract void Draw();
}

// 1. 원 클래스
public class Circle : Shape
{
    // Shape 추상 클래스와의 약속을 지키기 위해 Draw() 메서드를 반드시 구현(override)
    public override void Draw()
    {
        Console.WriteLine("원을 그립니다. ●");
    }
}

// 2. 사각형 클래스
public class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("사각형을 그립니다. ■");
    }
}

class Program
{
    static void Main()
    {
        // Shape 타입 변수에 자식 클래스 인스턴스를 담을 수 있다.
        Shape circle = new Circle { Color = "빨간색" };
        Shape rectangle = new Rectangle { Color = "파란색" };

        circle.Describe(); // 부모의 완성된 메서드 호출
        circle.Draw();     // 자식이 재정의한 메서드 호출 (다형성)

        rectangle.Describe(); // 부모의 완성된 메서드 호출
        rectangle.Draw();     // 자식이 재정의한 메서드 호출 (다형성)
    }
}

[실행 결과]

이 도형의 색상은 빨간색입니다.
원을 그립니다. ●
이 도형의 색상은 파란색입니다.
사각형을 그립니다. ■

추상 클래스는 객체로 만들 수 없지만, 자신을 상속받은 자식 클래스를
담는 변수 타입으로는 사용할 수 있습니다. 이것이 바로 다형성입니다.

4)인터페이스와 차이점은?

둘 다 미완성이라는 공통점이 있지만, 사용하는 목적과 철학이 다릅니다.

추상 클래스를 사용한다면...

  • 여러 관련 클래스 간에 코드를 공유하고 싶을 때. (공통 로직 제공)
  • 상속받는 클래스들이 공통된 필드나 protected, internal멤버가 필요할 때.
  • "이 클래스는 ~의 한 종류이다" 라는 is-a 관계가 명확할 때.

인터페이스를 사용한다면...

  • 서로 관련 없는 클래스들에게 특정 기능(역할)을 부여하고 싶을 때.
  • 다중 상속의 효과가 필요할 때.
  • "이 클래스는 ~을 할 수 있다" 라는 can-do 관계가 필요할 때.
profile
🚀 미래의 엔지니어를 꿈꾸는 훈련생의 기록 📝

0개의 댓글