클래스의 상속 -1

·2022년 5월 30일
0

cpp_study

목록 보기
10/25

사원 관리 프로그램

class Employee {
  std::string name;
  int age;
  std::string position; // 직책 (이름)
  int rank; // 순위 (값이 클 수록 높은 순위)
  
public:
  Employee(std::string name, int age, std::string position, int rank)
  : name(name), age(age), position(position), rank(rank) {}
  
  // 복사 생성자
  Employee(const Employee& employee) {
    name = employee.name;
    age = employee.age;
    position = employee.position;
    rank = employee.rank;
  }
  // 디폴트 생성자
  Employee() {}
  
  void print_info() {
    std::cout << name << " (" << position << " , " << age << ") ==> "
    << calculate_pay() << "만원" << std::endl;
  }
  
  int calculate_pay() { return 200 + rank * 50; }
};


class EmployeeList {
  int alloc_employee; // 할당한 총 직원 수
  int current_employee; // 현재 직원 수
  Employee** employee_list; // 직원 데이터
public:
  EmployeeList(int alloc_employee) : alloc_employee(alloc_employee) {
    employee_list = new Employee*[alloc_employee];
    current_employee = 0;
  }

  void add_employee(Employee* employee) {
    // 사실 current_employee 보다 alloc_employee 가 더
    // 많아지는 경우 반드시 재할당을 해야 하지만, 여기서는
    // 최대한 단순하게 생각해서 alloc_employee 는
    // 언제나 current_employee 보다 크다고 생각한다.
    // (즉 할당된 크기는 현재 총 직원수 보다 많음)
    employee_list[current_employee] = employee;
    current_employee++;
  }

  int current_employee_num() { return current_employee; }

  void print_employee_info() {
    int total_pay = 0;
    for (int i = 0; i < current_employee; i++) {
      employee_list[i]->print_info();
      total_pay += employee_list[i]->calculate_pay();
    }
    std::cout << "총 비용 : " << total_pay << "만원 " << std::endl;
  }
  
  ~EmployeeList() {
    for (int i = 0; i < current_employee; i++) {
      delete employee_list[i];
    }
    delete[] employee_list;
  }
  
};

이때 차장 이상 급들은 관리데이터에 근속 년수를 포함시켜서 월급에 추가해달라는 요청이 들어옴.
-> 이럴 경우 Manager 클래스를 추가하면서 Employee 클래스와 비슷하게 만들되, calculate_pay 함수부분을 다르게 해야 한다.

=> 그런데 calculate_pay 부분만 다르게 하자고 Employee 클래스를 거의 복붙해서 코드 양을 비효율적으로 늘릴 수는 없다.

상속(Inheritance)

Manager 클래스를 상속을 사용해서 덜 비효율적으로 코드를 작성해 보자.

Base와 Derived 클래스

#include <iostream>
#include <string>

class Base {
  std::string s;
public:
  Base() : s("기반") { std::cout << "기반 클래스" << std::endl; }
  void what() { std::cout << s << std::endl; }
};

class Derived : public Base {
  std::string s;
public:
  Derived() : Base(), s("파생") {
    std::cout << "파생 클래스" << std::endl;
    // Base 에서 what() 을 물려 받았으므로
    // Derived 에서 당연히 호출 가능하다
    what();
  }
};

int main() {
  std::cout << " === 기반 클래스 생성 ===" << std::endl;
  Base p;
  std::cout << " === 파생 클래스 생성 ===" << std::endl;
  Derived c;
  return 0;
}

class Derived : public Base는 Derived가 Base를 public 형식으로 상속을 받겠다는 의미가 된다.

❗ 또 하나 눈여겨 봐야 할 점은 Derived의 생성자 호출 부분이다.
Derived(): Base(), s("파생") 부분에서 초기화 리스트에서 Base를 통해 기반의 생성자를 먼저 호출한다.
이때 기반 클래스의 생성자를 명시적으로 호출하지 않을 경우 기반 클래스의 디폴트 생성자가 호출됨.

초기화 리스트 관련 ❓

결과 분석

what() 함수 호출 부분을 보자.
what() 함수는 Base에 정의가 되어있어 Derived의 s가 아니라 Base의 s가 출력되어 "기반"이라고 나오게 된다.

오버라이딩

이번에는 what 함수를 Derived에도 추가해보자.
사실 두 함수는 같은 이름이지만, 다른 클래스에 정의되어 있는 것이기 때문에 다른 함수로 취급된 거임.

#include <iostream>
#include <string>

class Base {
  std::string s;
public:
  Base() : s("기반") { std::cout << "기반 클래스" << std::endl; }
  void what() { std::cout << s << std::endl; }
};

class Derived : public Base {
  std::string s;
public:
  Derived() : Base(), s("파생") {
    std::cout << "파생 클래스" << std::endl;
    what();
  }
  void what() { std::cout << s << std::endl; }
};

int main() {
  std::cout << " === 기반 클래스 생성 ===" << std::endl;
  Base p;
  std::cout << " === 파생 클래스 생성 ===" << std::endl;
  Derived c;
  return 0;
}

Derived의 what 함수가 Base의 what 함수를 오버라이딩한 걸 볼 수 있음.

class 상속 접근 지시자

참고: https://velog.io/@choi_612/CPP4
class A : public(접근 지시자) B

public 상속

기반 클래스의 접근 지시자들에 영향 없이 그대로 작동

protected 상속

public 은 protected로 바뀜 나머지는 그대로 유지

private 상속

모든 접근 지시자들이 private으로 바뀜

profile
이것저것 개발하는 것 좋아하지만 서버 개발이 제일 좋더라구요..

0개의 댓글