이번 편의 목표: 부모 타입의 참조로 자식의 연체료 계산을 호출하고, 소멸자를 가상 함수로 둡니다.

상속은 부모의 공개 약속을 자식이 물려받는 관계입니다. virtual 함수는 호출 때 참조나 포인터가 실제로 가리키는 객체의 함수를 실행합니다. override는 부모의 가상 함수를 재정의한다는 검사입니다. 서명이 다르면 컴파일 오류가 납니다.

C++
#include <iostream>

class FeePolicy {
public:
    virtual ~FeePolicy() = default;
    virtual int fee(int days) const = 0;
};

class PaperFee : public FeePolicy {
public:
    int fee(int days) const override {
        return days * 100;
    }
};

class VideoFee : public FeePolicy {
public:
    int fee(int days) const override {
        return days * 300;
    }
};

void print_fee(const FeePolicy &policy, int days) {
    std::cout << policy.fee(days) << '\n';
}

int main() {
    PaperFee paper;
    VideoFee video;
    print_fee(paper, 3);
    print_fee(video, 3);
    return 0;
}

출력은 300과 900입니다. print_fee는 자식 타입을 모릅니다. fee가 virtual이므로 실제 객체의 함수가 실행됩니다. = 0이 붙은 함수는 순수 가상 함수이고, FeePolicy 자신은 객체를 만들 수 없습니다.

부모 포인터로 자식을 delete하려면 부모 소멸자가 virtual이어야 합니다. 그렇지 않으면 그 삭제의 의미가 정의되지 않습니다. 이번 예제는 참조로만 전달해 그 삭제를 만들지 않습니다. 값으로 FeePolicy policy = paper처럼 받으면 자식 부분이 잘려 부모만 남습니다. 다형성을 유지할 때는 값 복사가 아니라 참조나 포인터를 사용합니다.

직접 해 보기

VideoFee의 하루 요금을 500으로 바꾸고 2일의 결과가 1000인지 확인하세요.

해설

2 곱하기 500은 1000입니다. print_fee의 매개변수 타입은 계속 FeePolicy 참조입니다. 호출부에 VideoFee 객체를 넘기면 재정의한 fee가 실행됩니다.