KoreanFoodie's Study

C++ 기초 개념 6-1 : C++ 표준 문자열, 상속, 오버라이딩, protected 키워드 본문

Tutorials/C++ : Beginner

C++ 기초 개념 6-1 : C++ 표준 문자열, 상속, 오버라이딩, protected 키워드

GoldGiver 2022. 1. 6. 14:47

모두의 코드를 참고하여 핵심 내용을 간추리고 있습니다. 자세한 내용은 모두의 코드의 씹어먹는 C++ 강좌를 참고해 주세요!

표준 String 클래스

C++에서 문자열을 표현할 때는 char[ ]이 아닌, 표준 String 클래스를 사용하자.

 

 

상속

직원을 관리하는 EmployeeList와 Employee class를 만들었다고 가정해 보자.

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& e) {
		name = e.name;
		age = e.age;
		position = e.position;
		rank = e.rank;
	}

	Employee() {}

	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) {
		employee_list[current_employee] = employee;
		current_employee++;
	}

	~EmployeeList() {
		for (int i = 0; i < current_employee; ++i) {
			delete employee_list[i];
		}
		delete[] employee_list;
	}

};

 

만약 연차가 높은 사원은 따로 Manager class의 인스턴스로 관리해달라는 요청이 들어왔다고 가정해 보자. 이때, 새로운 manager 클래스는 Employee class에서 연차를 나타내는 변수 하나만 추가해서 만들면 된다. 만약 Manager 말고도 새로운 직급이 생긴다면..? 클래스 하나를 추가하기 위해 전체 코드를 뜯어고쳐야 한다.

이러한 문제점을 해결하기 위해 상속을 사용한다.

 

먼저, Base와 Derived 라는 예제 클래스를 한 번 만들어 보자.

class Base {
 protected:
  std::string parent_string;

 public:
  Base() : parent_string("기반") {  std::cout << "기반 클래스" <<  std::endl; }

  void what() {  std::cout << parent_string <<  std::endl; }
};

class Derived : public Base {
  std::string child_string;

 public:
  Derived() : Base(), child_string("파생") {
     std::cout << "파생 클래스" <<  std::endl;

    // 그렇다면 현재 private 인 Base 의
    // parent_string 에 접근할 수 있을까?
    parent_string = "바꾸기";
  }

  void what() {  std::cout << child_string <<  std::endl; }
};

int main() {
   std::cout << " === 기반 클래스 생성 ===" <<  std::endl;
  Base p;

   std::cout << " === 파생 클래스 생성 ===" <<  std::endl;
  Derived c;
}

위의 코드를 실행하면, what()이 Derived 클래스에서 오버라이딩되므로, 아래와 같은 결과가 출력된다.

 === 기반 클래스 생성 ===
기반 클래스
 === 파생 클래스 생성 ===
기반 클래스
파생 클래스

이때, Derived 클래스는 class Derived : public Base ... 와 같은 식으로 상속을 하고 있는데, 이때의 접근 지정자는 해당 접근 지정자로 멤버 변수와 함수를 받는다는 뜻이다. 즉, protected로 상속을 하면 public인 녀석들이 protected로 바뀌고, private으로 상속을 하면 모든 녀석들을 private하게 상속하겠다는 의미이다!

 

처음에 만들었던 Employee 클래스를 상속받은 Manager 클래스를 생성하면, 코드의 불필요한 반복과 낭비를 줄일 수 있다.

#include <iostream>
#include <string>

class Employee {
 protected:
  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 Manager : public Employee {
  int year_of_service;

 public:
  Manager(std::string name, int age, std::string position, int rank,
          int year_of_service)
      : Employee(name, age, position, rank), year_of_service(year_of_service) {}

  // 복사 생성자
  Manager(const Manager& manager)
      : Employee(manager.name, manager.age, manager.position, manager.rank) {
    year_of_service = manager.year_of_service;
  }

  // 디폴트 생성자
  Manager() : Employee() {}

  int calculate_pay() { return 200 + rank * 50 + 5 * year_of_service; }
  void print_info() {
    std::cout << name << " (" << position << " , " << age << ", "
              << year_of_service << "년차) ==> " << calculate_pay() << "만원"
              << std::endl;
  }
};
class EmployeeList {
  int alloc_employee;  // 할당한 총 직원 수

  int current_employee;  // 현재 직원 수
  int current_manager;   // 현재 매니저 수

  Employee** employee_list;  // 직원 데이터
  Manager** manager_list;    // 매니저 데이터

 public:
  EmployeeList(int alloc_employee) : alloc_employee(alloc_employee) {
    employee_list = new Employee*[alloc_employee];
    manager_list = new Manager*[alloc_employee];

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

  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();
    }
    for (int i = 0; i < current_manager; i++) {
      manager_list[i]->print_info();
      total_pay += manager_list[i]->calculate_pay();
    }
    std::cout << "총 비용 : " << total_pay << "만원 " << std::endl;
  }
  ~EmployeeList() {
    for (int i = 0; i < current_employee; i++) {
      delete employee_list[i];
    }
    for (int i = 0; i < current_manager; i++) {
      delete manager_list[i];
    }
    delete[] employee_list;
    delete[] manager_list;
  }
};
int main() {
  EmployeeList emp_list(10);
  emp_list.add_employee(new Employee("노홍철", 34, "평사원", 1));
  emp_list.add_employee(new Employee("하하", 34, "평사원", 1));
  emp_list.add_manager(new Manager("유재석", 41, "부장", 7, 12));
  emp_list.add_manager(new Manager("정준하", 43, "과장", 4, 15));
  emp_list.add_manager(new Manager("박명수", 43, "차장", 5, 13));
  emp_list.add_employee(new Employee("정형돈", 36, "대리", 2));
  emp_list.add_employee(new Employee("길", 36, "인턴", -2));
  emp_list.print_employee_info();
  return 0;
}
Comments