Menu
Coddy logo textTech

추상 클래스

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 60번째.

추상 클래스는 최소 하나 이상의 순수 가상 함수를 포함하는 모든 클래스를 의미합니다. 불완전한 인터페이스를 가지고 있기 때문에 추상 클래스의 객체를 직접 생성할 수 없으며, 오직 상속을 위해서만 존재합니다.

class Shape {
public:
    virtual double area() = 0;      // 순수 가상 함수 - Shape를 추상 클래스로 만듭니다
    virtual double perimeter() = 0; // 또 다른 순수 가상 함수
    
    void printInfo() {              // 일반 메서드 - 구현부가 있음
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // 오류: 추상 클래스를 인스턴스화할 수 없습니다

추상 클래스는 순수 가상 함수(구현 없음), 일반 가상 함수(기본 구현 포함), 그리고 비가상 함수를 혼합하여 포함할 수 있습니다. 이를 통해 공통된 동작을 정의하는 동시에 파생 클래스가 특정 기능을 구현하도록 요구할 수 있습니다.

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() override { return 3.14159 * radius * radius; }
    double perimeter() override { return 2 * 3.14159 * radius; }
};

Circle c(5.0);      // OK: Circle은 모든 순수 가상 함수를 구현합니다
c.printInfo();      // 상속된 printInfo()를 사용하며, Circle의 area()를 호출합니다

파생 클래스가 구체 클래스(인스턴스화 가능)가 되려면 모든 순수 가상 함수를 구현해야 합니다. 만약 하나라도 구현하지 않은 채로 두면, 그 클래스 자체도 추상 클래스로 남게 됩니다. 이 메커니즘은 계층 구조 내의 모든 구체 클래스가 필요한 기능을 제공하도록 보장합니다.

challenge icon

챌린지

쉬움

추상 클래스가 서로 다른 미디어 유형에 대한 계약을 정의하는 방법을 보여주는 미디어 플레이어 시스템을 구축해 보겠습니다. 모든 미디어 플레이어가 수행해야 하는 작업을 설정하는 추상 기본 클래스를 만든 다음, 오디오 및 비디오 콘텐츠를 위한 구체적인 플레이어를 구현합니다.

코드는 세 개의 파일로 구성됩니다:

  • MediaPlayer.h: 모든 미디어 유형의 청사진 역할을 하는 추상 MediaPlayer 클래스를 정의합니다. 추상 클래스에는 다음이 포함되어야 합니다:
    • protected std::string title 멤버
    • protected int duration 멤버 (초 단위)
    • 두 값을 초기화하는 생성자
    • 순수 가상 play() 메서드 — 각 미디어 유형은 다르게 재생됩니다.
    • std::string을 반환하는 순수 가상 getMediaType() 메서드
    • <title> (<duration>s) - Type: <mediaType>를 출력하는 일반(비가상) showInfo() 메서드 — 이 메서드는 getMediaType()을 호출하여 유형을 가져와야 합니다.
    • 가상 소멸자
  • Players.h: MediaPlayer를 상속받는 두 개의 구체적인 미디어 플레이어를 구현합니다:

    AudioPlayer:

    • private std::string artist 멤버
    • title, duration, artist를 인자로 받는 생성자
    • Playing audio: <title> by <artist>를 출력하도록 play() 구현
    • "Audio"를 반환하도록 getMediaType() 구현

    VideoPlayer:

    • private std::string resolution 멤버
    • title, duration, resolution을 인자로 받는 생성자
    • Playing video: <title> in <resolution>를 출력하도록 play() 구현
    • "Video"를 반환하도록 getMediaType() 구현
  • main.cpp: 네 개의 입력을 읽습니다 (각각 별도의 줄에 입력됨):
    1. 오디오 트랙 제목
    2. 오디오 재생 시간 (정수)
    3. 비디오 제목
    4. 비디오 재생 시간 (정수)

    artist를 "Unknown Artist"로 설정한 AudioPlayer와 resolution을 "1080p"로 설정한 VideoPlayer를 생성합니다. 두 객체를 MediaPlayer* 포인터 배열에 저장합니다.

    배열을 순회하며 각 플레이어에 대해 먼저 showInfo()를 호출한 다음 play()를 호출합니다. 각 미디어 항목 사이에 빈 줄을 출력합니다. 작업이 끝나면 동적으로 할당된 객체들을 정리합니다.

예를 들어, 입력값이 Summer Vibes, 180, Nature Documentary, 3600인 경우의 출력은 다음과 같습니다:

Summer Vibes (180s) - Type: Audio
Playing audio: Summer Vibes by Unknown Artist

Nature Documentary (3600s) - Type: Video
Playing video: Nature Documentary in 1080p

showInfo() 메서드가 추상 기본 클래스에서 한 번 정의되었지만 순수 가상 메서드인 getMediaType()을 호출하는 방식에 주목하세요. 이는 추상 클래스가 구체적인 구현과 파생 클래스에서 반드시 제공해야 하는 메서드를 어떻게 혼합할 수 있는지 보여줍니다. 모든 오버라이딩된 메서드에는 override 키워드를 사용하는 것을 잊지 마세요.

치트 시트

추상 클래스(abstract class)는 적어도 하나의 순수 가상 함수를 포함하며 직접 인스턴스화할 수 없습니다. 이는 상속을 위해 존재하며 파생 클래스를 위한 인터페이스를 정의합니다.

추상 클래스 정의하기

순수 가상 함수를 선언하려면 = 0을 사용하세요:

class Shape {
public:
    virtual double area() = 0;      // 순수 가상 함수
    virtual double perimeter() = 0; // Shape를 추상 클래스로 만듭니다
    
    void printInfo() {              // 구현부가 있는 일반 메서드
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;     // 가상 소멸자
};

추상 클래스는 다음을 포함할 수 있습니다:

  • 순수 가상 함수 (구현부 없음)
  • 일반 가상 함수 (기본 구현부 포함)
  • 비가상 함수

구체 클래스 구현하기

파생 클래스가 인스턴스화 가능해지려면 모든 순수 가상 함수를 구현해야 합니다:

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() override { return 3.14159 * radius * radius; }
    double perimeter() override { return 2 * 3.14159 * radius; }
};

Circle c(5.0);      // OK: 모든 순수 가상 함수가 구현됨
c.printInfo();      // 상속된 메서드가 Circle의 area()를 호출함

파생 클래스가 모든 순수 가상 함수를 구현하지 않으면, 해당 클래스는 여전히 추상 클래스로 남게 되며 인스턴스화할 수 없습니다.

직접 해보기

#include <iostream>
#include <string>
#include "MediaPlayer.h"
#include "Players.h"

int main() {
    // 입력 읽기
    std::string audioTitle;
    int audioDuration;
    std::string videoTitle;
    int videoDuration;
    
    std::getline(std::cin, audioTitle);
    std::cin >> audioDuration;
    std::cin.ignore();
    std::getline(std::cin, videoTitle);
    std::cin >> videoDuration;
    
    // TODO: artist가 "Unknown Artist"인 AudioPlayer 생성
    
    // TODO: resolution이 "1080p"인 VideoPlayer 생성
    
    // TODO: 둘 다 MediaPlayer* 포인터 배열에 저장
    
    // TODO: 배열을 순회하며 각 플레이어에 대해:
    //       1. showInfo() 호출
    //       2. play() 호출
    //       3. 각 미디어 항목 사이에 빈 줄 출력
    
    // TODO: 동적으로 할당된 객체 정리
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨