Menu
Coddy logo textTech

순수 가상 함수

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

순수 가상 function은 기본 클래스에 구현이 없는 가상 function입니다. function 선언에 = 0을 할당하여 선언합니다. 이는 파생 클래스가 자체 구현을 반드시 제공해야 한다는 것을 컴파일러에 알립니다.

class Shape {
public:
    virtual double area() = 0;  // 순수 가상 함수
    virtual ~Shape() = default;
};

기본 동작을 제공하는 일반 가상 함수와 달리, 순수 가상 함수는 계약을 정의합니다. 즉, 모든 구체적인 파생 class는 인스턴스화 가능하도록 이 function을 구현해야 합니다. 기본 class는 단순히 무엇을 해야 하는지만 선언할 뿐, 어떻게 해야 하는지는 선언하지 않습니다.

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

class Rectangle : public Shape {
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double area() override {
        return width * height;
    }
};

CircleRectangle은 모두 Shape에서 순수 가상 함수이므로 area()를 구현해야 합니다. 파생 class가 모든 순수 가상 함수를 구현하지 않으면 해당 class도 추상 class가 되어 인스턴스화할 수 없습니다.

순수 가상 함수는 기본 클래스가 의미 있는 기본 구현을 제공할 수 없을 때 필수적입니다. 모든 도형에는 area가 있지만, 특정 도형 유형을 알지 않고는 “일반적인 도형 area”를 calculate할 합리적인 방법이 없습니다.

challenge icon

챌린지

쉬움

서로 다른 결제 방식에서 순수 가상 함수가 어떻게 계약을 강제하는지 보여 주는 결제 처리 시스템을 만들어 보겠습니다. 모든 결제 프로세서가 수행해야 하는 작업을 정의하는 추상 기본 클래스를 만든 다음, 해당 계약을 충족하는 구체적인 결제 유형을 구현합니다.

코드를 세 개의 파일로 구성합니다.

  • PaymentProcessor.h: 모든 결제 방식의 청사진 역할을 하는 추상 PaymentProcessor 클래스를 정의합니다. 이 클래스에는 다음이 있어야 합니다.
    • protected std::string accountId 멤버
    • 계정 ID를 초기화하는 생성자
    • 순수 가상 processPayment(double amount) 메서드: 각 결제 유형은 이를 서로 다른 방식으로 구현해야 합니다.
    • std::string을 반환하는 순수 가상 getProcessorName() 메서드
    • 가상 소멸자
  • PaymentMethods.h: PaymentProcessor를 상속하는 두 개의 구체적인 결제 프로세서를 구현합니다.

    CreditCardProcessor:

    • private double feePercentage 멤버(거래 수수료율)
    • 계정 ID와 수수료율을 받는 생성자
    • 수수료를 계산한 후 출력하도록 processPayment()를 구현합니다(amount * feePercentage / 100). 출력 형식:
      Credit Card [<accountId>]: Charged $<amount> (Fee: $<fee>)
    • "CreditCard"를 반환하도록 getProcessorName()을 구현합니다.

    BankTransferProcessor:

    • private std::string bankName 멤버
    • 계정 ID와 은행 이름을 받는 생성자
    • 다음 형식으로 출력하도록 processPayment()를 구현합니다:
      Bank Transfer [<accountId>] via <bankName>: Transferred $<amount>
    • "BankTransfer"를 반환하도록 getProcessorName()을 구현합니다.
  • main.cpp: 네 개의 입력을 읽습니다(각각 별도의 줄에 입력).
    1. 신용 카드 계정 ID
    2. 신용 카드 수수료율(double)
    3. 은행 계정 ID
    4. 은행 이름

    두 결제 프로세서를 생성하고 PaymentProcessor* 포인터 배열에 저장합니다. 각 프로세서를 통해 100.0의 결제를 처리하고, 각 거래 전에 프로세서 이름을 표시합니다.

    Processing with <processorName>:
    <processPayment output>

    프로세서 사이에 빈 줄을 출력합니다. 작업이 끝나면 동적으로 할당한 객체를 정리합니다.

예를 들어 입력이 CC-4521, 2.5, BA-7890, National Bank인 경우:

Processing with CreditCard:
Credit Card [CC-4521]: Charged $100 (Fee: $2.5)

Processing with BankTransfer:
Bank Transfer [BA-7890] via National Bank: Transferred $100

PaymentProcessor에는 순수 가상 함수가 있으므로 이를 직접 인스턴스화할 수 없습니다. 계약을 충족하는 구체적인 구현만 생성할 수 있습니다. 이를 통해 모든 결제 방식이 자체적인 특정 처리 로직을 제공하도록 보장합니다.

직접 해보기

#include <iostream>
#include <string>
#include "PaymentMethods.h"

using namespace std;

int main() {
    // 입력 읽기
    string ccAccountId;
    double feePercentage;
    string bankAccountId;
    string bankName;
    
    getline(cin, ccAccountId);
    cin >> feePercentage;
    cin.ignore();
    getline(cin, bankAccountId);
    getline(cin, bankName);
    
    // TODO: 요소가 2개인 PaymentProcessor* 포인터 배열 생성
    
    // TODO: CreditCardProcessor와 BankTransferProcessor 객체 생성
    // 그리고 배열에 저장
    
    // TODO: 배열을 순회하며 각 프로세서에 대해:
    // 1. Print "Processing with <processorName>:"
    // 2. 금액 100.0으로 processPayment 호출
    // 3. 프로세서 사이에 빈 줄 출력 (마지막 이후에는 하지 않음)
    
    // TODO: 동적으로 할당된 객체 정리
    
    return 0;
}
quiz icon실력 점검

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

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

직접 연습해 보세요: 온라인 C++ 컴파일러