반응형
안녕하세요? 수구리입니다.
지난 포스팅에서는 C++의 유니폼 초기화에 대해서 알아보았었죠?
2021.08.20 - [C++] - [C++] 유니폼 초기화란?
이번 포스팅에서는 이전에 Employee 클래스관련 예제들을 확장해서 직원 관리 콘솔 프로그램을 한번 만들어 보도록 하겠습니다!
먼저 실행화면부터 보겠습니다.
대충 이런 형태입니다.
우선 1번부터 0번까지 사용자가 입력할 수 있도록 대기상태이구요
해당 목록을 입력하면 직원을 등록, 해고, 승진 시킬 수 있고
모든 직원을 조회하거나 현재 직원만 조회 또는 지금은 일하고 있진 않지만 이전에 일했던 직원들의 목록까지 출력해줍니다.
그리고 종료를 하려면 0을 입력하면 프로그램이 종료가 됩니다!
예시로 홍길동이라는 사람을 추가한 뒤, 4번을 입력해서 조회해보도록 하겠습니다.
이렇게 현재 직원 정보가 모두 출력이 되어지는데요~
Employee Number와 Salary는 입력하지 않아도 자동으로 입력된 모습입니다.
default 값이 존재한다는 말이겠죠?
계속 사원이 1명씩 추가되면 1001, 1002, ... 이렇게 증가해 나갈 것입니다!
그러면 자세한 구현으로 넘어가보도록 하겠습니다!
1.6 첫 C++ 프로그램
- 이번 파트에서는 앞서 배운 내용들을 토대로 하여 간단한 콘솔 프로그램을 만들어 볼 예정이다.
- 앞서 했었던 예제 중, 직원 데이터베이스 예제를 확장한 버전이다.
1.6.1 직원 관리 시스템
- 이 시스템은 아래와 같은 기능을 제공한다.
- 직원 채용
- 직원 해고
- 직원 승진
- 과거와 현재 직원 모두 조회
- 현재 직원 모두 조회
- 과거 직원 모두 조회
- Employee 클래스는 직원 한 명에 대한 정보를 표현
- Database 클래스는 모든 직원을 관리함
- UserInterface 를 통해서 프로그램을 다루도록 함.
1.6.2 Employee 클래스
Employee.h
// Employee.h
#pragma once // 같은 파일을 여러번 불러오지 않도록 함.
#include <string>
// Records라는 네임스페이스에 속하도록 선언
namespace Records {
// 신입직원의 기본 급여 정의
const int kDefaultStartingSalary = 30000; // 상수는 앞에 k를 붙이는 관례
class Employee
{
public:
// default 생성자 & 성, 이름을 받는 생성자
Employee() = default;
Employee(const std::string& firstName, const std::string& lastName);
// 정수 type의 매개변수를 받음. 기본값이 정해져 있어서 매개변수가 없다면 default값으로
void promote(int raiseAmount = 1000);
void demote(int demeritAmount = 1000);
void hire(); // 직원 고용
void fire(); // 직원 해고.
void display() const;// 직원 정보 콘솔 출력
// getter & setter
void setFirstName(const std::string& firstName);
const std::string& getFirstName() const;
void setLastName(const std::string& lastName);
const std::string& getLastName() const;
void setEmployeeNumber(int employeeNumber);
int getEmployeeNumber() const;
void setSalary(int newSalary);
int getSalary() const;
bool isHired() const;
// 다른 코드에서 수정하지 못하도록 private로 데이터 맴버 선언
private:
std::string mFirstName;
std::string mLastName;
int mEmployeeNumber = -1;
int mSalary = kDefaultStartingSalary;
bool mHired = false;
};
}
Employee.cpp
- 생성자는 성, 이름을 인수로 받아 각각의 값을 해당 데이터 맴버에 설정하기만 한다.
// Employee.cpp
#include <iostream>
#include "Employee.h"
using namespace std;
namespace Records {
// 성, 이름을 받아 각각의 값을 해당 데이터 맴버에 설정.
Employee::Employee(const std::string& firstName, const std::string& lastName)
: mFirstName(firstName)
, mLastName(lastName)
{
}
// 인수로 전달된 값을 의미에 맞게 바꿔서 setSalary 메서드로 전달.
void Employee::promote(int raiseAmount)
{
setSalary(getSalary() + raiseAmount);
}
void Employee::demote(int demeritAmount)
{
setSalary(getSalary() - demeritAmount);
}
// mHired 변수 설정하는 고용, 해고 메서드
void Employee::hire()
{
mHired = true;
}
void Employee::fire()
{
mHired = false;
}
// 현재 직원에 대한 정보를 콘솔 출력.
void Employee::display() const
{
cout << "Employee: " << getLastName() << ", " << getFirstName() << endl;
cout << "-------------------------" << endl;
cout << (isHired() ? "Current Employee" : "Former Employee") << endl;
cout << "Employee Number: " << getEmployeeNumber() << endl;
cout << "Salary: $" << getSalary() << endl;
cout << endl;
}
// getter & setter
void Employee::setFirstName(const string& firstName)
{
mFirstName = firstName;
}
const string& Employee::getFirstName() const
{
return mFirstName;
}
void Employee::setLastName(const string& lastName)
{
mLastName = lastName;
}
const string& Employee::getLastName() const
{
return mLastName;
}
void Employee::setEmployeeNumber(int employeeNumber)
{
mEmployeeNumber = employeeNumber;
}
int Employee::getEmployeeNumber() const
{
return mEmployeeNumber;
}
void Employee::setSalary(int salary)
{
mSalary = salary;
}
int Employee::getSalary() const
{
return mSalary;
}
bool Employee::isHired() const
{
return mHired;
}
}
EmployeeTest.cpp
- 위의 작성된 코드를 간단하게 아래의 테스트 코드를 가지고 테스트 해보자.
// EmployeeTest.cpp
#include <iostream>
#include "Employee.h"
using namespace std;
using namespace Records;
int main()
{
cout << "Testing the Employee class." << endl;
Employee emp;
emp.setFirstName("John");
emp.setLastName("Doe");
emp.setEmployeeNumber(71);
emp.setSalary(50000);
emp.promote();
emp.promote(50);
emp.hire();
emp.display();
return 0;
}
1.6.3 Database 클래스
- Database 클래스는 표준 라이브러리에서 제공하는 std::Vector 클래스를 이용하여 Employee 객체를 저장한다.
Database.h
- 신입 직원에 대한 직원번호는 DB에서 자동으로 할당.
- 직원 번호의 시작값을 상수로 설정
// Database.h
// std::vector 클래스를 이용하여 Employee 객체 저장
#pragma once
#include <iostream>
#include <vector>
#include "Employee.h"
namespace Records {
// 신입 직원에 대한 직원번호는 DB 내부에서 자동 할당을 위해 시작값을 상수로 정의
const int kFirstEmployeeNumber = 1000;
class Database
{
public:
// 성, 이름으로 신입 직원 추가
Employee& addEmployee(const std::string& firstName,
const std::string& lastName);
// 직원번호로 직원 조회
Employee& getEmployee(int employeeNumber);
// 성, 이름으로 직원 조회
Employee& getEmployee(const std::string& firstName,
const std::string& lastName);
// 모든 직원 정보를 출력
void displayAll() const;
// 현재 재직중인 직원 정보 출력
void displayCurrent() const;
// 퇴사한 직원 정보 출력
void displayFormer() const;
private:
// mEmployees는 Employee 객체를 가지고 있는 배열
std::vector<Employee> mEmployees;
// 신입직원에 할당된 직원 번호를 기록하며 상수로 초기화
int mNextEmployeeNumber = kFirstEmployeeNumber;
};
}
Database.cpp
// Database.cpp
#include <iostream>
#include <stdexcept>
#include "Database.h"
using namespace std;
namespace Records {
// 새로운 Employee 객체 생성 후 vector에 추가
Employee& Database::addEmployee(const string& firstName, const string& lastName)
{
Employee theEmployee(firstName, lastName);
// 다음 직원이 새로운 번호를 받기위해 1 증가
theEmployee.setEmployeeNumber(mNextEmployeeNumber++);
theEmployee.hire();
mEmployees.push_back(theEmployee);
return mEmployees[mEmployees.size() - 1];
}
// 범위기반 for문을 사용하여 mEmployees에 있는 모든 직원을 돌면서
// 전달된 직원번호와 같은 직원을 찾는다.
Employee& Database::getEmployee(int employeeNumber)
{
for (auto& employee : mEmployees) {
if (employee.getEmployeeNumber() == employeeNumber) {
return employee;
}
}
// 없다면 예외 발생
throw logic_error("No employee found.");
}
// 직원의 성, 이름을 받아와 해당 직원이 있는지 조회
Employee& Database::getEmployee(const string& firstName, const string& lastName)
{
for (auto& employee : mEmployees) {
if (employee.getFirstName() == firstName &&
employee.getLastName() == lastName) {
return employee;
}
}
// 없다면 예외 발생
throw logic_error("No employee found.");
}
// 모든 직원에 대하여 Loop를 돌면서 일정 조건에 만족하는
// 직원의 정보를 콘솔에 출력
void Database::displayAll() const
{
for (const auto& employee : mEmployees) {
employee.display();
}
}
// 현재 재직중인 모든 직원 정보를 출력한다.
void Database::displayCurrent() const
{
for (const auto& employee : mEmployees) {
if (employee.isHired())
employee.display();
}
}
// 과거에 다녔었던 직원을 조회한다.
void Database::displayFormer() const
{
for (const auto& employee : mEmployees) {
if (!employee.isHired())
employee.display();
}
}
}
DatabaseTest.cpp
- 마찬가지로 위의 Database 클래스가 잘 동작하는지 확인해보자.
// DatabaseTest.cpp
// 정의한 Database의 기본 기능을 정의하는 테스트 코드
#include <iostream>
#include "Database.h"
using namespace std;
using namespace Records;
int main()
{
Database myDB;
Employee& emp1 = myDB.addEmployee("Greg", "Wallis");
emp1.fire();
Employee& emp2 = myDB.addEmployee("Marc", "White");
emp2.setSalary(100000);
Employee& emp3 = myDB.addEmployee("John", "Doe");
emp3.setSalary(10000);
emp3.promote();
cout << "all employees: " << endl << endl;
myDB.displayAll();
cout << endl << "current employees: " << endl << endl;
myDB.displayCurrent();
cout << endl << "former employees: " << endl << endl;
myDB.displayFormer();
return 0;
}
1.6.4 사용자 인터페이스
- 앞서 말했듯이 콘솔 응용프로그램이므로 메뉴 기반으로 사용자가 직원 데이터베이스에 쉽게 접근할 수 있도록 한다.
#include <iostream>
#include <stdexcept>
#include <exception>
#include "Database.h"
using namespace std;
using namespace Records;
int displayMenu();
void doHire(Database& db);
void doFire(Database& db);
void doPromote(Database& db);
void doDemote(Database& db);
int main()
{
Database employeeDB;
bool done = false;
while (!done) {
int selection = displayMenu();
switch (selection) {
case 0:
done = true;
break;
case 1:
doHire(employeeDB);
break;
case 2:
doFire(employeeDB);
break;
case 3:
doPromote(employeeDB);
break;
case 4:
employeeDB.displayAll();
break;
case 5:
employeeDB.displayCurrent();
break;
case 6:
employeeDB.displayFormer();
break;
default:
cerr << "Unknown command." << endl;
break;
}
}
return 0;
}
int displayMenu()
{
// 화면에 메뉴를 출력 -> 사용자의 입력을 받음.
// 숫자를 요청하면 숫자를 입력한다고 가정.
// 잘못된 입력이 들어오면 예외 처리
int selection;
cout << endl;
cout << "Employee Database" << endl;
cout << "-----------------" << endl;
cout << "1) Hire a new employee" << endl;
cout << "2) Fire an employee" << endl;
cout << "3) Promote an employee" << endl;
cout << "4) List all employees" << endl;
cout << "5) List all current employees" << endl;
cout << "6) List all former employees" << endl;
cout << "0) Quit" << endl;
cout << endl;
cout << "---> ";
cin >> selection;
return selection;
}
void doHire(Database& db)
{
// 신입직원의 이름을 입력받아 DB에 그 직원에 대한 정보 추가요청
string firstName;
string lastName;
cout << "First name? ";
cin >> firstName;
cout << "Last name? ";
cin >> lastName;
db.addEmployee(firstName, lastName);
}
void doFire(Database& db)
{
int employeeNumber;
cout << "Employee number? ";
cin >> employeeNumber;
try {
Employee& emp = db.getEmployee(employeeNumber);
emp.fire();
cout << "Employee " << employeeNumber << " terminated." << endl;
}
catch (const std::logic_error& exception) {
cerr << "Unable to terminate employee: " << exception.what() << endl;
}
}
void doPromote(Database& db)
{
int employeeNumber;
int raiseAmount;
cout << "Employee number? ";
cin >> employeeNumber;
cout << "How much of a raise? ";
cin >> raiseAmount;
try {
Employee& emp = db.getEmployee(employeeNumber);
emp.promote(raiseAmount);
}
catch (const std::logic_error& exception) {
cerr << "Unable to promote employee: " << exception.what() << endl;
}
}
void doDemote(Database& db) {
int employeeNumber;
int demeritAmount;
cout << "Employee number? ";
cin >> employeeNumber;
cout << "How much of a demerit? ";
cin >> demeritAmount;
try
{
Employee& emp = db.getEmployee(employeeNumber);
emp.demote(demeritAmount);
}
catch (const std::logic_error& exception)
{
cerr << "Unable to demote employee. " << exception.what() << endl;
}
}
반응형
'🌈 프로그래밍 > C++' 카테고리의 다른 글
[C++] 동적 스트링 Part 2 (0) | 2021.08.25 |
---|---|
[C++] 동적 스트링 Part 1 (2) | 2021.08.24 |
[C++] 유니폼 초기화란? (2) | 2021.08.20 |
[C++] 객체 지향 언어의 특성에 대하여 (0) | 2021.08.20 |
[C++] 타입 추론에 대하여 (0) | 2021.08.20 |