C++. ATM Project ver.3

lsw·2021년 4월 2일
0

Mini Projects

목록 보기
3/11
post-thumbnail

1. 업그레이드 항목

  • 기존 통합계좌를 입금시 마다 원금에 이자율을 곱한값을 추가 입금해 주는(이자를 추가로 입금해 주는) "Normal" 저축 계좌와 이자율에 특별이자율을 더한값을 곱해 추가해주는 "High" 저축계좌로 나눠볼 예정이다. 특히 High 계좌 유형은 고객등급에 따라 재차 A등급 계좌, B등급 계좌, C등급 계좌로 나뉘

2. 주의점

  • 기존 Handler class의 원형을 최대한 유지한 채 Normal, High 클래스만 생성한다.
  • 상속을 이용하며 함수 오버라이딩과 virtual선언 활용을 유의한다.
  • 인터페이스를 조금이나마 개선한다.

3. 코드

  • Header file : account.h
#pragma once

// 고객 등급별(NORMAL, HIGH) 상이한 이자율을 적용하기 위해 이름공간 "TYPE"에 문자 열거(enum)
namespace TYPE 
{
	enum
	{
		NORMAL = 1, HIGH
	};
}

// 옵션에 해당하는 문자들에 정수의미 부여
enum
{
	MAKE = 1, DEPOSIT, WITHDRAW, SHOW, EXIT
};

// 고객명, 계좌번호 배열 길이에 일관성을 두기위해 전역변수 생성.
const int NAME_LEN = 30;
const int ID_LEN = 30;

/***Account class**
  Account 클래스는 
1. 실제 객체생성을 할 필요가 없는 명목 클래스
2. Normal, High 클래스의 기초 클래스
3. Entity 클래스
이다.
*/
class Account
{
private:
	char* acc_id; // 계좌번호
	char* acc_name; // 성명
	double acc_balance; // 잔금

// 생성자, 복사생성자, 소멸자 선언
/*명목클래스인데도 생성자, 복사생성자를 생성하는 이유
  : Account 클래스를 상속할 유도클래스 들의 생성자, 복사생성자가 참조할 수 있게 하기 위해
*/
public:
	Account(const char* acc_id, const char* acc_name, double acc_seed);
	Account(Account& copy);
	~Account();

// 기타 재료함수 선언
// 계좌번호 반환
	char* Get_id();
// 잔금 반환
	double Get_balance();
/* virtual!!
  추후 오버라이딩될 Proccess_depos(입금함수)를 이에 접근하는 객체 클래스에 맞춰 
  호출할 수 있도록 보장해주는 장치
*/ 
// 입금함수
  virtual void Proccess_depos(double money);
// 출금함수
	void Proccess_withdraw(double money);
// 조회함수
	void Showinform();

};

/*Accounthandler class*/
class Accounthandler // controller or handler 클래스로서 기능적인 역할을 수행한다.
{
private:
	Account* acc[100]; // 길이가 100인 Account 배열 객체 선언
	int acc_count; // 고객 고유번호
public:
// 생성자, 소멸자 (**백업**을 위해선 **복사생성자** 또한 선언해야 하지만 배제함을 가정하겠음)
	Accounthandler();
	~Accounthandler(); 
// 기능함수 선언(메뉴, 개설, 입금, 출금, 조회)
	void Menu();
	void Make();
	void Deposit();
	void Withdraw();
	void Show();
};

/*Normal class*/
class Normal : public Account // Account 클래스를 상속받는 유도클래스
{
private:
	double acc_rate; // 일반 이자율

public:
// 생성자
	Normal(const char* id, const char* name, double seed, double rate);
// 입금함수 오버라이딩1	
void Proccess_depos(double money);
// 이자율 반환   
double Getrate();
};

class High : public Normal // Account 클래스의 하위클래스인 Normal클래스를 상속받는 High클래스
{
private:
// 고객 등급에 따라 특별이자율을 결정
  char acc_type; // 고객등급
  double acc_srate; // 특별이자율

public:
	High(char* id, char* name, double seed, double rate, char type);
// 입금함수 오버라이딩2
	void Proccess_depos(double money);
};
  • Function file : account.cpp
#include "account.h" // 헤더파일 참조
#include<iostream>
#include<cstring>  // for the use of strcpy, strcmp
using namespace std;

/*Account class*/
/*생성자*/
Account::Account(const char* Acc_id, const char* Acc_name, double acc_seed)
	:acc_balance(acc_seed)
{
// 동적할당
	int len1 = strlen(Acc_id) + 1;
	int len2 = strlen(Acc_name) + 1;
	acc_id = new char[len1];
	acc_name = new char[len2];
	strcpy(acc_id, Acc_id);
	strcpy(acc_name, Acc_name);
}

/*복사생성자*/
Account::Account(Account& copy)
{
	int len1, len2;
	len1 = strlen(copy.acc_id) + 1;
	len2 = strlen(copy.acc_name) + 1;
	acc_id = new char[len1];
	acc_name = new char[len2];
	strcpy(acc_id, copy.acc_id);
	strcpy(acc_name, copy.acc_name);
}

/*소멸자*/
Account::~Account()
{
	delete[]acc_id;
	delete[]acc_name;
}

/*기타 함수*/
// 계좌 반환
char *Account::Get_id()
{
	return acc_id;
}
// 잔금 반환(소수자리 표현)
double Account::Get_balance()
{
	return acc_balance;
}

/*입금함수*/
/* 굳이 별도 정의를 내리지 않고, 순수 가상함수로 만들어 클래스 자체를 
   가상클래스화 하는 것이 바람직하나 아직 적용하지 않겠음 */
void Account::Proccess_depos(double money)
{
	acc_balance += money;
}
// 출금함수
void Account::Proccess_withdraw(double money)
{
	acc_balance -= money;
}
// 조회함수
void Account::Showinform()
{
	cout << "계좌번호 : " << acc_id << endl;
	cout << "고객이름 : " << acc_name << endl;
	cout << "잔액 : " << acc_balance;
}

--------------------------------------------------------------------------------------
/*Normal class*/
// 생성자
Normal::Normal(const char* Acc_id, const char* Acc_name, double acc_seed, double rate)
: acc_rate(rate), Account(Acc_id, Acc_name, acc_seed) // 기초클래스의 생성자 참조(호출)
{
}

// 입금함수(일반 이자율 고려)
void Normal::Proccess_depos(double money) // virtual을 추가 선언할 필요는 없다. 생략가능
{
// **총 입금액 = 원 입금액 + 원금*일반이자율**
  Account::Proccess_depos(money+Account::Get_balance()*acc_rate) ; 
}
// 이자율 반환
double Normal::Getrate()
{
  return acc_rate;  
}

--------------------------------------------------------------------------------------
/*High class*/
// 생성자
High::High(char* id, char* name, double seed, double rate, char type)
: Normal(id, name, seed, rate) // 기초클래스인 Normal 클래스의 생성자 참조(호출)
{
// 등급(char type 매개변수를 통해 복사된 인자값)에 따른 특별이자율 초기화
  switch(type)
  {
    case 'A':
    {
      acc_srate = 0.07;
      break;
    }
    case 'B':
    {
      acc_srate = 0.04;
      break;
    }
    case 'C':
    {
      acc_srate = 0.02;
      break;
    }
    default:
    {
      cout << "유형을 재입력 하세요" << endl;
    }
  }
}

// 입금함수. 일반이자율 & 특별이자율 고려
void High::Proccess_depos(double money)
{
// 총 입금액 = 원 입금액 + 원금*(일반이율 + 특별이율)
  Account::Proccess_depos(money+ Get_balance()*(Getrate()+acc_srate)); 
}

---------------------------------------------------------------------------------------
/*Accounthandler class*/
// 생성자
Accounthandler::Accounthandler()
	:acc_count(0) // 0부터 고객번호 시작
{
}

// 소멸자
// 동적할당으로 생성될 객체배열 인자 acc[i]를 소멸
Accounthandler::~Accounthandler()
{
	for (int i = 0; i < acc_count; i++)
	{
		delete acc[i]; // 동적할당 소멸
	}
}

// 기능 함수 정의
// 메뉴창
void Accounthandler::Menu()
{
	cout << "-------------------------------------------------" << endl;
	cout << "가능 업무" << endl;
	cout << "1. 계좌 생성 "<< endl;
	cout << "2. 입금" << endl;
	cout << "3. 출금" << endl;
	cout << "4. 조회" << endl;
	cout << "5. 프로그램 종료" << endl;
}

// 개설
void Accounthandler::Make()
{
	char acc_id[ID_LEN];
	char acc_name[NAME_LEN];
	int acc_balance;
  int type;
	cout << "계좌번호 : "; cin >> acc_id;
	cout << "성명     : "; cin >> acc_name;
	cout << "예치금   : "; cin >> acc_balance;
  cout << "[계좌유형 결정]" << endl;
  cout << "(Normal=1/High=2) : " ; cin >> type; // 계좌 유형에 따라..
  double rate;
  char acc_level;
// 계좌 생성 방법이 다르다(서로 다른 타입의 동적할당)
  switch(type)
  {
// 일반등급 계좌, 일반이율만 기입하며 Normal 클래스형으로 동적할당함
    case TYPE::NORMAL:
    {
      cout << "이율   : " ; cin >> rate; // 일반이율 입력
// Account 객체배열인자 동적할당(i=0 ~ )
      acc[acc_count++] = new Normal(acc_id, acc_name, acc_balance, rate); 
      break;
    }
    case TYPE::HIGH: // 일반이율, 고객등급을 모두 적시해야 하며 High클래스형으로 동적할당
    {
      cout << "이율   : " ; cin >> rate; // 일반이율
      cout << "고객등급 : " ; cin >> acc_level; // 고객등급 적시
// 동적할당
      acc[acc_count++] = new High(acc_id, acc_name, acc_balance, rate, acc_level);
    }
  }
}

// 입금함수(virtual, overriding)
void Accounthandler::Deposit()
{
// 입금관련 고객정보 입력
	char id[ID_LEN];
	int money;
	cout << "계좌번호 입력 : "; cin >> id; // 계좌번호 입력
	for (int i = 0; i < acc_count; i++) 
	{
		if (strcmp(acc[i]-> Get_id(), id) ==0) // 계좌번호 반환함수 호출, 일치 확인
		{
			cout << "금액(만원) : "; cin >> money; // 입금액 입력
/*
 Proccess_depos 함수는 virtual선언이 된 가상함수이다. 따라서 등급별(Normal / High)로 다르게
 동적할당된 객체배열인자 acc[i]들 각각의 클래스에 해당하는 함수를 호출하게 된다
*/ 
			acc[i] -> Proccess_depos(money);
			cout << "정상 입금 되었습니다." << endl;
      break;
		}
    else if(i==acc_count - 1) // 계좌번호 불일치 시
			cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
	}
}
// 출금함수
void Accounthandler::Withdraw()
{
// 거래관련 정보 입력
	char id[ID_LEN];
	int money;
	cout << "계좌번호 입력 : "; cin >> id; // 계좌번호 입력
	for (int i = 0; i < acc_count; i++)
	{
		if (strcmp(acc[i]-> Get_id(), id) ==0) // 계좌번호 일치 확인
		{
			cout << "금액(만원) : "; cin >> money; // 출금액 입력
// 출금함수는 계좌유형에 상관없이 **동일기능**을 요구하기 때문에 virtual선언하지 않는다.
			acc[i] -> Proccess_withdraw(money); 
			cout << "정상 출금 되었습니다." << endl;
		}
		else if(i == acc_count - 1) // 불일치 시
			cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
	}
}
// 조회함수
void Accounthandler::Show()
{
  cout << "------------------" ;
	for (int i = 0; i < acc_count; i++)
	{
    cout << endl << "[" << i << "번째 고객 정보]" << endl;
		acc[i]->Showinform(); // Account의 조회함수 호출
    cout << " 만원" << endl << endl;
	}
}
  • main file : main.cpp
#include "account.h" 
#include <iostream>
#include<cstring>
using namespace std; // for the use of strcmp

int main()
{
	Accounthandler AH; // Accounthandler 클래스 객체를 생성해 멤버함수에 접근
	int choice;
	while (1)
	{
		AH.Menu(); // 메뉴창
		cout << "거래를 선택하세요 : "; cin >> choice; // 거래유형 선택
		switch (choice)
		{
		case MAKE: // 생성
		{
			AH.Make(); 
			break;
		}
		case DEPOSIT: // 입금
		{
			AH.Deposit();
			break;
		}
		case WITHDRAW: // 출금
		{
			AH.Withdraw();
			break;
		}
		case SHOW: // 조회
		{
			AH.Show();
			break;
		}
		case EXIT: // 종료
		{
			cout << "거래를 종료합니다." << endl;
			return 0;
		}
		default: // 옵션에 벗어난값 입력 시
		{
			cout << "다른 옵션을 선택하세요" << endl;
		}
	}
		char further[5];
		cout << "거래를 계속 하시겠습니까?(yes / no) : "; cin >> further;
		if (strcmp(further, "no") == 0)
		{
			return 0;
		}
	}
	return 0;
}

4.1 Normal 계좌 결과

  1. Normal 계좌 생성
  2. 입금, 정상입금 확인(일반 이율 이자 지급)
  3. 정상 출금 확인
  4. 종료 확인

4.2 High 계좌 결과

  1. High 계좌 생성
  2. 입금, 정상 입금 확인(이율 + 특별이율 이자 지급)
  3. 정상 출금 확인
  4. 종료 확인


5. 결론

상속의 사용으로 하나의 공유(가상, 부모, 기초)클래스를 두고 여러 성격이 다른 유도클래스를 정의하여 활용할 수 있다.

profile
미생 개발자

0개의 댓글