C++. ATM Project ver.2

lsw·2021년 3월 30일
0

Mini Projects

목록 보기
2/11
post-thumbnail

1. 업그레이드

There will be a version update to cover couple of "new" notions

notions be..

  • Constructor & Destructor
  • Copy Constructor
  • classify Entity & Controller(Handler) class
  • Inheritance(just check about the possibility.. whether related to something like "A is B" or "A has B")

Look at the code first..!


1. 코드

account.h

#pragma once

// 전역변수 생성(문자열 길이의 일관성)
const int NAME_LEN=30;
const int ID_LEN=30;
// 정수 의미를 갖는 문자 열거
enum 
{
	MAKE=1, DEPOSIT, WITHDRAW, SHOW, EXIT
};

/*Account class*/
class Account // entity class : 고객 계좌관련 신상정보가 저장되는 클래스
{
private: // 생략가능
	char* acc_id; // 계좌번호, "-"기호를 받아들이기 위해 문자열 타입으로 변경
	char* acc_name; // 성명
	int acc_balance; // 잔금(원금)

public:
//생성자
	Account(const char* acc_id, const char* acc_name, int acc_seed);
// 복사생성자
	Account(Account& copy); 
// 소멸자
	~Account(); // 프로그램 종료 직전 동적할당으로 생성된 멤버변수(문자열) 소멸

/*기타 함수*/
// 계좌번호 반환
	char *Get_id(); 
// 잔금 반환
	int Get_balance();
// 입금 처리
	void Proccess_depos(int money);
// 출금 처리
	void Proccess_withdraw(int money);
// 고객정보 조회
	void Showinform();
};

/*Accounthandler class*/
class Accounthandler  
// controller class, Account와 관련된 기능(1. 개설, 2. 입급 ~ ~ ~ 5. 종료)수행 클래스
{
private:
	Account* acc[100]; // Account 클래스 타입 길이 100짜리 배열
	int acc_count; // 고객 고유번호

public:
// 디폴트(무 인자) 생성자
	Accounthandler(); 
// 소멸자
	~Accounthandler(); 
  // 멤버변수에 동적할당이 필요한 배열 acc가 있다. 이를 제거하기 위한 소멸자 
/*기능 관련 함수*/
// 기능관련 함수들이 멤버 내로 영입(?) 됨으로써 정보은닉의 효과를 누릴 수 있다.(접근 제한)
// 메뉴창
	void Menu(); 
// 개설
	void Make();
// 입금
	void Deposit();
// 출금
	void Withdraw();
// 조회
	void Show();
};

account.cpp

#include "account.h" // 헤더파일 참조
#include<iostream>
#include<cstring> // string related functions
using namespace std;

/*Account class*/
/*생성자*/
Account::Account(const char * Acc_id, const char* Acc_name, int 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);
} 

/*복사 생성자*/
/* **<디폴트 이외 복사생성자를 정의하는 이유>**
   디폴트 복사생성자를 이용한 초기화(복사)가 진행되면 각 멤버변수 간의 얕은복사가 진행된다.
   이 때 문자열 변수의 경우 얕은복사가 진행되면 하나의(기존 객체 멤버변수가 가리키는) 주소
   를 기존, 복사자 두 객체의 멤버변수가 공유하여 가리키는 꼴이 된다. 이 때 기존 또느 복사자
   의 객체가 소멸되면(destructed) 공유 주소 역시 소멸되어 나머지 한 객체의 변수는 가리키는
   주소가 없어지게 된다. 이 상태에서 그 나머지 객체가 소멸되면(소멸자를 호출하면) 소멸할 대
   상이 없는 에러가 발생하게 된다(다만 컴파일은 된다). 따라서 문자열을 포함하는 객체의 
   복사생성자는 디폴트 이외 별도 복사생성자를 정의하여야 하는 것이다. 
*/
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;
}
// 잔금 반환
int Account::Get_balance()
{
	return acc_balance;
}
// 입금 처리과정
void Account::Proccess_depos(int money)
{
	acc_balance += money; // 금액 초기화
}
// 출금 처리과정
void Account::Proccess_withdraw(int money)
{
	acc_balance -= money; // 금액 초기화
}
// 조회
void Account::Showinform()
{
	cout << "계좌번호 : " << acc_id << endl;
	cout << "고객이름 : " << acc_name << endl;
	cout << "잔액 : " << acc_balance << endl << endl;
}

-

/*Accounthandler class*/

/*생성자*/
Accounthandler::Accounthandler()
	:acc_count(0) // 0부터 고객번호 시작
{}
/*소멸자*/
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;
	cout << "계좌번호 : "; cin >> acc_id;
	cout << "이름 : "; cin >> acc_name;
	cout << "예치금 : "; cin >> acc_balance;
// 입력받은 정보를 인자로 한 계좌 생성(동적할당)
	acc[acc_count++] = new Account(acc_id, acc_name, acc_balance); 
}
// 입금
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)
/* acc[]는 Account의 포인터형 이기에, Account 함수에 "->" 방식으로 접근. 
   입력아이디 일치여부 확인
*/ 
		{
			cout << "금액 : "; cin >> money; // 거래 금액 입력
			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;
			acc[i] -> Proccess_withdraw(money); // 출금 처리 함수 호출
			cout << "정상 출금되었습니다." << endl;
      break;
		}
		else if(i == acc_count-1)
			{
         cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
      }
	}
}

// 조회
void Accounthandler::Show()
{
	for (int i = 0; i < acc_count; i++)
	{
		acc[i]->Showinform(); // Account class의 고객정보 조회함수 호출
	}
}

main.cpp

#include "account.h" // account 헤더파일 참조
#include <iostream>
#include <cstring>
using namespace std;

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

—-

2. 결과

  • Console sequence
  1. 1 입력(개설), 정보입력
  2. 2 입력(입금), 입금 금액 입력

  • Console sequence
  1. 4 입력(조회, 정상 입금 확인)
  2. 3 입력(출금), 출금금액 입력

  1. 4 입력(정상 출금 확인)

3. 결론

핵심은 깊은복사를 위한 디폴트가 아닌 복사생성자의 정의와 entity / controller 클래스의 구분 생성이었다. 단순 정보를 담는 역할인 Account 클래스와 기능관련 함수를 내포하는 Accounthandler 클래스를 정의해 보았다.

profile
미생 개발자

0개의 댓글