C++.(P.5) 회사내 직원 급여정보 프로젝트(ver.1)

lsw·2021년 4월 1일
0

Mini Projects

목록 보기
11/11
post-thumbnail

1. 개요

신천 기업은 이번달 신입사원 공채를 진행하기 앞서 그들의 신상정보와 계약형태, 부서, 근무지역별 급여(한달) 정보를 저장하며 필요시 요약하여 볼 수 있는 기능이 필요, 관련해 SW Si기업에 외주를 맡겼다. 담당자 이모씨의 구상을 살펴보자


2. Rough algorithm

  1. '직원(Employee)' 이라는 공유 클래스를 설정한 후 하위 클래스를 설정한다. 부서, 지역이 어찌되었건 그들은 '신입 직원' 이다.
  2. 새로운 직무, 부서가 추가되어도 기능 클래스의 조작이 필요하지 않도록 구현하기 위해 virtual function개념을 도입한다.
  3. 기능 함수를 만든다(직원정보 / 총급여 출력)

3. Code

이역시 파일분리를 진행하기엔 머리가 터질거같아 우선 하나의 파일에 담아보았다.

  • Employee class(공유 모체)
#include<iostream>
#include<cstring>
using namespace std;

const int name_len = 100;

class Employee // 유령 클래스 or 모체 클래스
{
// 직원명, 계약형태(정규직, 비정규직)
private:
	char name[name_len];
	char contract[name_len];

public:
	Employee(const char* Name, const char* Contract)
	{
		strcpy(name, Name);
		strcpy(contract,  Contract);
	}

// 아래 함수는 모두 추후 사용을 목적으로 함
	char* Getname()
	{
		return name;
	}

	char* Getcontract()
	{
		return contract;
	}
/* 포인터 초기화 -> 포인터로의 함수 접근시 해당 타입(클래스)의 함수 이용을 원칙으로 하는 
   c++이다. 추가적인 부서를 공유 class Employee 하위클래스(유도)로 설정하고, 기능 클래스에서
   Employee class 타입의 포인터로만 접근하고자 한다면 초기화대상인 객체의 타입은 존중(팔로잉)
   해주는 장치가 필요하다. 
   showinfo(), Getsalary()함수는 추후 계속 같은 이름으로 오버라이딩되어 선언과 정의에 문제가 
   없고, virtual지정 덕에 포인터가 가리키는 객체형의 멤버변수에 접근할 수 있게 되었다.
   ....설명이 길었다.... 
*/

/* 추가적으로
  virtual void showinfo() =0과 동일한 문이나, 컴파일러의 문제인지 오류가 발생한다.
  const를 유지할 시 객체타입에 상관없이 virtual을 무시하고 const {}가 유지되어 이 방법을 차선
  으로 택했다.
*/
	virtual void showinfo() 
  {

  }

	virtual int Getsalary()
  {
    return 0; // int type이니 반환값이 반드시 있어야한다!
  }
};
  • Permanent class(정규직)
class Permanent : public Employee // Employee를 상속받는다
{
private:
	int salary;

public:
	Permanent(const char* name, int salary)
		: Employee(name, "정규직"), salary(salary)
	{
	}

	int Getsalary() // 오버라이딩으로 문제x 상위클래스 '동일명(동일매개변수)' 함수 무시
	{
		return salary;
	}

	void showinfo() // 마찬가지
	{
		cout << "직원명 : " << Getname() << endl;
		cout << "계약형태 : " << Getcontract() << endl;
		cout << "급여 : " << Getsalary() << "만원"<< endl <<endl;
	}
};
  • Sales class(정규직, 영업사원)
class Sales : public Permanent
{
// 영업사원은 실적에 따라 특별히 인센티브를 제공하는게 A사 원칙
private:
	char department[name_len]; //부서
	double incentrate; // 인센
	int done; // 실적

public:
	Sales(const char* name, int salary, double incent)
		: Permanent(name, salary), incentrate(incent), department("영업부"), done(0)
	{

	}
	int Getdone()
	{
		return done;
	}

	void adddone(int plus)
	{
		done += plus;
	}

// 오버라이딩
	int Getsalary()
	{
		return (int)(Permanent::Getsalary() + (done * incentrate));
	}

	void showinfo()
	{
		cout << "사원명 : " << Getname() << endl;
		cout << "계약형태 : " << Getcontract() << endl;
		cout << "부서 : " << department << endl;
		cout << "급여 : " << Getsalary() << "만원"<<endl<<endl;
	}
	char* Getdepart()
	{
		return department;
	}

};
  • ForeignSales class(해외, 오지 영업부)
// enumerate를 위해 이름공간 별도 생성
namespace RISK_INCENT
{
	enum
	{
		L = 1, M, H  // risk high ~ low
	};
}

class ForeignSales : public Sales
{
private:
  int riskincent;
	char subdepart[name_len];

public:
	ForeignSales(const char* name, int salary, double incentrate, int riskincecnt)
		: Sales(name, salary, incentrate), riskincent(riskincecnt), subdepart("외지팀")
	{

	}
// 실적 추가 함수
   void adddone(int plus)
   {
     Sales::adddone(plus);
   }

	int Getsalary()
	{
		return (int)(Sales::Getsalary() * (1 + (double)riskincent / 10));
	}

	void showinfo()
	{
		cout << "사원명 : " << Getname() << endl;
		cout << "계약형태 : " << Getcontract() << endl;
		cout << "부서(팀) : " << Getdepart() << "(" << subdepart << ")" << endl;
		cout << "급여 : " << Getsalary() << "만원"<<endl << endl;
	}
};
  • Temporary class(임시직)
class Tempor : public Employee
{
private:
// 시간제 급여 시스템 : 시간, 시급, 한달중 출근 일수
	int hour;
	double sal_perhour;
  int day;
public:
	Tempor(const char* name)
		: Employee(name, "비정규직"), hour(0), sal_perhour(0.7), day(0)
	{

	}

// 하루 일한 시간 추가
	void addhour(int Hour)
	{
		hour += Hour;
	}
// 한달중 일한날 추가
  void addday(int Day)
  {
    day += Day;
  }

	int Getsalary()
	{
		return hour * sal_perhour * day;
	}

	void showinfo()
	{
		cout << "사원명 : " << Getname() << endl;
		cout << "계약형태 : " << Getcontract() << endl;
		cout << "급여 : " << Getsalary() << "만원"<<endl << endl;
	}
};
  • Controller class(직원정보 관련 기능 함수 포함)
class Handler
{
private:
	Employee* emp[100]; // Employee type pointer variable 'emp'
	int empnum; // count num
public:
	Handler()
		: empnum(0)
	{

	}
// 직원 추가
	void addemployee(Employee* Emp) // new 동적할당자를 인자로 받아야함(call by reference)
	{
		emp[empnum++] = Emp;
	}
// 직원정보(신상, 급여..)
	void showperspectinfo()
	{
		for (int i = 0; i < empnum; i++)
		{
			emp[i]->showinfo(); // emp가 가리키는 객체타입의 클래스 멤버함수 접근, 호출!!
		}
	}

	void showtotalsalary()
	{
		int total = 0;
		for (int i = 0; i < empnum; i++)
		{
			total += emp[i]->Getsalary(); // 이하 동일
		}
		cout << "이번달 총 급여액 : " << total << "만원" << endl;
	}
};
  • main function
	int main()
{
// 기능(멤버 함수)사용을 위해 Handler class 변수 디폴트 생성
	Handler handle;

	// 정규직 채용  char* name, int salary, double incent)
  /* Permanent class 는 별도 사용 멤버함수가 없기에 곧바로 handle.add(new ~)할당하여 
     포인터를 생성하지 않았다. */
	handle.addemployee(new Permanent("이상원", 300)); 
	handle.addemployee(new Permanent("이영기", 350));

	//영업부 채용, 별도함수 adddone()접근을 위해 해당타입 포인터변수 생성
	Sales* salman1 = new Sales("이민호", 320, 0.2);
	salman1->adddone(200);
	handle.addemployee(salman1); // 직원 채용

	//영어부-오지탐사팀 채용, 동일
	ForeignSales* fs1 = new ForeignSales("김병만", 320, 0.2, RISK_INCENT::H);
	fs1->adddone(250);
	ForeignSales* fs2 = new ForeignSales("베어그릴스", 330, 0.2, RISK_INCENT::M);
	fs2->adddone(400);
	handle.addemployee(fs1); // 채용
	handle.addemployee(fs2);

	// 알바생 채용, 동일
	Tempor* temp1 = new Tempor("김민석");
	temp1->addhour(8);
  temp1->addday(20);
	Tempor* temp2 = new Tempor("이석환");
	temp2->addhour(3);
  temp2 -> addday(8);
	handle.addemployee(temp1);
	handle.addemployee(temp2);
  cout << "---------------------" << endl; 
	handle.showperspectinfo();
	cout << "---------------------" << endl << endl;
	handle.showtotalsalary();

	return 0;
}

4. 결과

결과가 예쁘게 잘 나왔다!





5. 느낀점

성격이 다양한 객체를 상속을 통해 공통 클래스로 묶(?)고 행여 하위 클래스가 추가되더라도 컨트롤러에서 제약없이, 변경없이 접근할 수 있음에 놀랐다. 객체지향의 우월성을 깨달아가고 있으며 점차 entity / controller의 구분을 명확히 할 수 있을것 같다.

profile
미생 개발자

0개의 댓글