[07-1] 상속에 들어가기에 앞서

김민성·2022년 8월 1일
post-thumbnail

상속에 대한 새로운 관점의 이해

C++의 상속은 그 단어의 의미처럼 물려 받는다는 성격이 강하다. 따라서 과거에서는 다음과 같은 생각을 가지고 상속을 바라봐 왔다.

"기존에 정의해 놓은 클래스의 재활용을 목적으로 만들어진 문법적 요소가 상속이다."

물론 상속에는 이러한 이점도 존재하지만, 이는 '상속'을 적용하는 근본적인 이유가 되지는 않는다. '상속'에 대해 새로운 관점으로 바라보자.

문제의 제시를 위한 시나리오의 도입

예제를 하나 살펴보자. OrangeMedia라는 회사가 운영하는 '급여관리 시스템'이다.

EmployeeManager1.cpp의 PermanentWorker 클래스 정의

class PermanentWorker
{
    private:
        char name[100];
        int salary; //매달 지불해야 하는 급여액

    public:
        PermanentWorker(char* name, int money)
            :salary(money)
        {
            strcpy(this->name, name);
        }
        int GetPay() const
        {
            return salary;
        }
        void ShowSalaryInfo() const
        {
            cout<<"name: "<<name<<endl;
            cout<<"salary: "<<GetPay()<<endl<<endl;
        }
};

이름과 급여정보를 저장할 수 있도록 클래스를 정의했다.

다음은 위에서 정의한 클래스의 객체를 저장 및 관리하기 위한 클래스이다. PermanentWorker 객체의 저장을 목적으로 배열을 멤버로 지니고 있으며, 저장된 객체의 급여 정보를 출력하기 위한 함수를 멤버로 지니고 있다.

EmployeeManager1.cpp의 EmployeeHandler 클래스 정의

class EmployeeHandler
{
    private:
        PermanentWorker* empList[50];
        int empNum;
    public:
        EmployeeHandler() : empNum(0)
        { }
        void AddEmployee(PermanentWorker* emp)
        {
            empList[empNum++]=emp;
        }
        void ShowAllSalaryInfo() const
        {
            for(int i=0; i<empNum; i++)
                empList[i]->ShowSalaryInfo();
        }
        void ShowTotalSalary() const
        {
            int sum=0;
            for(int i=0; i<empNum; i++)
                sum+=empList[i]->GetPay();
            cout<<"salary sum: "<<sum<<endl;
        }
        ~EmployeeHandler()
        {
            for(int i=0; i<empNum; i++)
                delete empList[i];
        }
};
  • 새로운 직원정보의 등록 : AddEmployee
  • 모든 직원의 이번 달 급여정보 출력 : ShowAllSalaryInfo
  • 이번 달 급여의 총액 출력 : ShowTotalSalary

이 클래스를 통해 이 프로그램이 어떠한 기능을 제공하는지 알 수 있다. 이를 '컨트롤 클래스' 또는 '핸들러 클래스'라 한다.

마지막으로 위의 두 클래스를 기반으로 main 함수를 작성해보자.

EmployeeManager1.cpp의 main 함수의 정의

int main(void) 
{
    //직원관리를 목적으로 설계된 컨트롤 클래스의 객체생성
    EmployeeHandler handler;

    //직원 등록
    handler.AddEmployee(new PermanentWorker("KIM", 1000));
    handler.AddEmployee(new PermanentWorker("LEE", 1500));
    handler.AddEmployee(new PermanentWorker("JUN", 2000));

    //이번 달에 지불해야 할 급여의 정보
    handler.ShowAllSalaryInfo();

    //이번 달에 지불해야 할 급여의 총합
    handler.ShowTotalSalary();
    return 0;
}

문제의 제시

만약 OrangeMedia 회사가 성장해 고용형태, 급여의 형태의 변화가 생긴다면, 앞서 보여준 예제를 어떻게 수정할 것인가?

고용형태는 다음과 같을 것이다.

  • 정규직(Permanent)
  • 영업직(Sales) : 조금 특화된 형태의 고용직. 인센티브 개념 도입
  • 임시직(Temporary) : 학생들을 대상으로 하는 임시고용 형태, 흔히 아르바이트라 함.

급여의 형태는 다음과 같을 것이다.

  • 고용직 급여 : 연봉제. 매달의 급여가 정해져 있음.
  • 영업직 급여 : 기본급여 + 인센티브
  • 임시직 급여 : 시간당 급여 x 일한 시간

그럼 다음과 같이 쉽게 생각할 수 있다.

"영업직을 의미하는 SalesMan 클래스, 임시직을 의미하는 Temporary 클래스를 추가하자."

하지만, 이를 추가하면 EmployeeHandler 클래스가 어떻게 변경되어야 할까..

"SalesMan 객체와 Temporary 객체의 저장을 위한 배열을 2개 추가하고, 각각의 배열에 저장된 객체의 수를 별도로 세어야 하니, 정수형 변수도 멤버로 2개 추가해야 하네."

여기서 끝이 아니다.

"AddEmployee 함수는 SalesMan, Temporary 객체용으로 각각 추가되어야 하고, 급여정보를 출력하는 나머지 두 멤버함수는 총 3개의 배열을 대상으로 연산을 진행해야 하니까, 반복문이 추가로 각각 2개씩 더 삽입되어야 하는군.."

결과적으로 그냥 통째로 바뀌는 것이다. 이는 좋은 코드구성이 될 수가 없다. 좋은 코드를 짜기 위해선 어떤 방법을 사용해야 할까?

바로 "상속"을 적용하면 앞서 말한 문제점을 간단히 해결할 수 있다. 다음 시간부터 알아보자.

profile
다양한 활동을 통해 인사이트를 얻는 것을 즐깁니다. 저 또한 인사이트를 주는 사람이 되고자 합니다.

0개의 댓글