C++. ATM Project ver.final
95358 ワード
1.最終更新
異常処理(異常処理)
例外処理について...
預金時に1元未満の値を入力すると、異常処理が行われます
引き出し時に入力した金額が残高より高い場合は例外処理を行います
(If you wanna know detailed explanation about exception handling notion, check back to series C++ → exception handling course.. uploaded before)
コードコメント
これまで6回更新されたATMプロジェクトの最新バージョンコードをまとめ、コメントします.
2.シーケンス
3.ATMプロジェクト最終コメント
each header-source pair
string pair(string.h - string.cpp)
文字列に関連
string.h
/*string.h*/
#pragma once // 중복 참조 방지
#include<iostream>
using namespace std;
class String
{
private:
int len;
char* str;
public:
// 디폴트 생성자(동적할당 - 깊은복사)
String();
// 인자를 갖는 생성자
String(const char* Str);
// 복사생성자(복사 시 동적할당(깊은복사) : 선언 & 복사)
String(const String& scopy);
// 대입연산자(복사 시 동적할당(깊은복사) : 선언 -> 복사)
String& operator=(const String& scopy);
// str에 str2을 이어붙인 값을 반환(strcat역할)
String operator+(const String& str2);
// str에 str2을 이어붙인 값으로 str을 재초기화
String& operator +=(const String& str2);
// 두 문자열의 일치 비교(strcmp의 역할)
bool operator==(const String& str2);
// string 출력, const선언
friend ostream& operator<<(ostream& cout, const String& str);
// string 입력(입력이기에 no const)
friend istream& operator>>(istream& cin, String& str);
};
string.cpp/*string.cpp*/
#include "string.h"
#include <iostream>
#include<cstring>
#include <cstdlib>
using namespace std;
// 디폴트 생성자 정의, len=0, str=NULL 값이 저장된다.
String::String()
{
len = 0;
str = 0;
}
// 인자가 있는 생성자 정의
String::String(const char* Str)
{
len = strlen(Str) + 1; // '\n'을 포함할 길이 1 추가
str = new char[len]; // 동적할당
strcpy(str, Str); // 문자열 복사
}
// 복사생성자 정의
String::String(const String& scopy)
{
len = scopy.len + 1;
str = new char[len]; // 동적할당
strcpy(str, scopy.str); // 복사
}
// 대입연산자의 정의
String& String::operator=(const String& scopy)
{
len = scopy.len + 1;
str = new char[len];
strcpy(str, scopy.str);
return *this;
}
// str에 str2이어붙인 값을 반환하는 함수('+'연산자 오버로드 함수)
String String::operator+(const String& str2)
{
// 좌피연산자가 디폴트 생성 객체 시 exit
if (str == NULL)
{
exit(1);
}
// 이미 '\n'을 위한 공간 1은 기존 len에 의해 확보. 중복에 의한 길이 1을 빼준다
int len2 = len + str2.len - 1;
// 초기화가 아닌 반환임에, 템포러리 변수를 지정해 준다.
char* tempstr = new char[len2];
// 임시변수에 str문자열을 복사
strcpy(tempstr, str);
// str문자열 공간 뒤에 str2.str을 이어붙임
strcat(tempstr, str2.str);
String temps(tempstr); // tempstr 를 인자로 받는 생성자 호출을 통해 String 객체 생성
return temps; // 반환(초기화x)
}
// 초기화 까지 진행하는 연산자 '+=' 오버로드 함수
String& String::operator +=(const String& str2)
{
// 마찬가지 디폴트 생성 객체 시 exit(오류)발생
if (str == NULL)
{
exit(1);
}
*this = *this + str2; // 바로 위에서 정의한 '+'연산자 오버로드 함수를 호출, 재초기화
return *this; // 초기화된 str을 반환하는 모습
}
// 두 string 일치 비교 함수, boolean
bool String::operator==(const String& str2)
{
if (str == NULL)
{
exit(1);
}
if (strcmp(str, str2.str) == 0)
// 두 문자열이 같다면
return true; // true 반환
else
// 두 문자열이 다르다면
return false; // false 반환
}
// 출력 : '<<'연산자 오버로드 함수
ostream& operator<<(ostream& cout, const String& str1)
// 여기 cout에는 특정한 의미가 없다. 단지 ostream 객체 참조형 변수일 뿐.
{
cout << str1.str << endl; // str1객체의 str변수를 출력한다.
return cout;
}
// 입력 : '>>'연산자 오버로드 함수
istream& operator>>(istream& cin, String& str1)
{
char str[100]; // 길이 100짜리 변수 생성
cin >> str; // 변수 초기화
str1 = String(str); // 대입연사자 호출, 해당변수를 인자로 받는 String객체로 복사진행
return cin;
}
#pragma once
#include "string.h"
#include<iostream>
using namespace std;
// Account class, Account * type인 ACCOUNT_PTR 형 선언
class Account;
typedef Account* ACCOUNT_PTR;
// 고객 등급과 관련한 이름공간 정의
namespace TYPE
{
enum
{
NORMAL = 1, HIGH
};
}
// 기능과 관련된 문자에 수의 의미를 담는 열거(enumerating)
enum
{
MAKE = 1, DEPOSIT, WITHDRAW, SHOW, EXIT
};
/*기존 고객명, 고객계좌번호의 길이를 전역변수 선언을 이용해 정했다면, String class객체 이용
시 입력받은 문자의 길이로 문자열의 길이를 할당하므로 이를 생략할 수 있다*/
// virtual class(만약 순수가상함수로 지정 시 실제 객체생성 불가능)
/*Account class*/
class Account
{
private:
// 문자열 변수인 계좌번호, 이름을 String 객체로 생성
String acc_id;
String acc_name;
double acc_balance; // 잔액
// 생성자
public:
Account(String acc_id, String acc_name, double acc_seed);
// 기타 재료함수(추후 접근용)
String Get_id(); // 계좌번호 반환
double Get_balance(); // 계좌 잔액 반환
virtual void Proccess_depos(double money)=0;
/*입금함수 : 계좌 유형별 상이한 입금과정(이율로인한)에 의해 다르게 정의될 예정이며(오버로드)
함수 접근 시 접근객체의 클래스에 맞는 오버로드함수 호출을 위해 virtual선언을 한 모습.
Account클래스는 객체생성이 불필요한 클래스로, 순수가상 클래스로 지정하기 위해 입금 함수를
순수가상 함수로 정의하는 모습 (=0)*/
void Proccess_withdraw(double money); // 출금 함수
// 배열 인자들의 각 타입에 맞는 출력함수(Showinform function의 역할)
// (declared with 'friend' to access Accountclass member variables)
friend ostream& operator<<(ostream& cout, Account& ref); // 반환형이 참조형일때
friend ostream& operator<<(ostream& cout, ACCOUNT_PTR& Aref); // 반환형이 포인터형일때
};
account.cpp#include "account.h"
#include "string.h"
#include<iostream>
using namespace std;
/*about Account class*/
/*생성자*/
Account::Account(String Acc_id, String Acc_name, double acc_seed)
:acc_balance(acc_seed)
{
// String클래스의 대입연산자 호출, 깊은복사 진행
acc_id = Acc_id;
acc_name = Acc_name;
}
/*기타 함수*/
// 계좌번호 반환
String Account::Get_id()
{
return acc_id;
}
// 계좌 잔액 반환(소수점 표현을 위해 double)
double Account::Get_balance()
{
return acc_balance;
}
/*입금함수 오버로드 1*/
// virtual 선언
void Account::Proccess_depos(double money)
{
acc_balance += money;
}
// 출금함수
void Account::Proccess_withdraw(double money)
{
acc_balance -= money; // 잔액을 줄이고
}
// 전역함수("<<"operator overload functions)
ostream& operator<<(ostream& cout, Account& ref)
{
cout << "계좌번호 : " << ref.acc_id ;
cout << "성명 : " << ref.acc_name ;
cout << "잔액 : " << ref.acc_balance << endl;;
return cout;
}
ostream& operator<<(ostream& cout, ACCOUNT_PTR& pref)
{
cout << *(pref);
/*
*(ACCOUNT_PTR) = Account
<< Account 는 바로 위 "<<"연산자 오버로드 함수 호출 시그널
*/
return cout;
}
#include "account.h"
#include "string.h"
#pragma once
class Normal : public Account
{
private:
double acc_rate; // 일반 이율
public:
// 생성자
Normal(String id, String name, double seed, double rate);
// 입금함수 오버로드 2
void Proccess_depos(double money);
// 일반이율 반환함수
double Getrate();
};
normal.cpp#include "account.h"
#include "normal.h"
/*about Normal class*/
// 생성자
Normal::Normal(String Acc_id, String Acc_name, double acc_seed, double rate)
: acc_rate(rate), Account(Acc_id, Acc_name, acc_seed) // Account클래스 생성자 차용
{
}
// 입금함수 오버로드 2
void Normal::Proccess_depos(double money)
{
// 총 입금액 = 입금액 + 잔액*이율
Account::Proccess_depos(money + Account::Get_balance() * acc_rate);
}
/*
두가지 옵션 존재
1. normal클래스의 변수 접근성을 protected로 완화하여 high클래스에서 acc_rate에 직접 접근
할 수 있도록 함
2. 지금과 같이 변수접근성은 private으로 유지하며(정보은닉의 장점) 별도 이율 반환함수룰
정의한다.
*/
// 이율 반환 함수
double Normal::Getrate()
{
return acc_rate;
}
#include "normal.h"
#include "string.h"
#pragma once
class High : public Normal
{
private:
// 고객등급 - 특별이율 변수
char acc_type;
double acc_srate;
public:
// 생성자
High(String id, String name, double seed, double rate, char type);
// 입금함수 오버로드 3
void Proccess_depos(double money);
};
high.cpp#include "high.h"
#include "account.h"
High::High(String id, String name, double seed, double rate, char type)
: Normal(id, name, seed, rate)
{
// 인자로 입력받은 등급별 상이한 이율 제공(초기화)
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;
}
}
}
// 입금함수 오버로드 3
void High::Proccess_depos(double money)
{
// 총 입금액 = 입금액 + 원금*(이율 + 특별이율)
Account::Proccess_depos(money + Account::Get_balance() * (Getrate() + acc_srate));
}
#include <iostream>
#pragma once
using namespace std;
/*Accountarray클래스 템플릿*/
template <typename T> // 템플릿 인자 T
class Accountarray
{
private:
T * arr;
int len; // 배열 길이
/* 배열의 고유성 보장을 위해 복사와 관련한 복사생성자, 대입연산자는 접근성 'private'으로
제한 */
Accountarray(Accountarray& Acopy);
Accountarray& operator=(Accountarray& Acopy);
public:
/* 배열의 디폴트 길이를 100으로 하고자 함. 따라서 배열 길이에 대한 'len'인자를 받는
생성자를 별도 정의하지 않겠음 -> 배열길이는 변함없이 100일 것이라는 얘기*/
Accountarray(); // 디폴트 생성자
T& operator[](int idx); // 피연산자가 const선언되지 않았을때 호출되는 함수
T operator[](int idx) const; // 피연산자가 const선언되었을때 호출되는 함수
int Getlen(); // 배열길이 반환함수
~Accountarray(); // 동적할당으로 생성된 배열 소멸을 위한 소멸자
};
accountarray.cpp#include "accountarray.h" // headerfile
#include <cstdlib> // exit..
#include "account.h"
#include <iostream>
/*생성자*/
template <typename T>
Accountarray<T>::Accountarray()
:len(100) // 디폴트 len = 100
{
arr = new T[100]; // 템플릿 인자에 맞는 동적할당
}
/*'[]'operator overload function 1(no const)*/
template <typename T>
T& Accountarray<T>::operator[](int idx)
{
// out of range
if (idx < 0 || idx >= len)
{
cout << "out of range" << endl;
exit(1);
}
return arr[idx];
/* 템플릿인자 T의 참조형 반환(no const라는 말은 접근하여 변경할 여지가 있다는 말. 따라서
참조형으로 반환한다*/
}
/*'[]'operator overload function 2(const)*/
template <typename T>
T Accountarray<T>::operator[](int idx) const
{
// out of range
if (idx < 0 || idx >= len)
{
cout << "out of range" << endl;
exit(1);
}
return arr[idx]; // const피연산자의 호출이기에 변경여지x -> 템플릿인자 체로 반환
}
/*소멸자*/
template <typename T>
Accountarray<T>::~Accountarray()
{
delete []arr; // 프로그램 종료 전 동적할당 삭제
}
#pragma once
/*예외처리 클래스*/
/*기초클래스*/
class Accountexp // exception 클래스 통합관리 기초클래스
{
int money;
public:
// 생성자
Accountexp(int moeny);
virtual void Showmessage()=0; // 순수가상 함수 - 순수가상클래스화
};
/*유도클래스 1(입금 시 예외처리 클래스)*/
class Depositexp : public Accountexp
{
int money;
public:
Depositexp(int money);
// 함수오버로드 1
void Showmessage();
};
/*유도클래스 2(출금 시 예외처리 클래스)*/
class Withdrawexp : public Accountexp
{
int money;
public:
Withdrawexp(int money);
// 함수오버로드 3
void Showmessage();
};
exception.cpp#include "exception.h"
#include <iostream>
using namespace std;
/*기초 예외처리 클래스*/
// 생성자
Accountexp::Accountexp(int money):money(money){};
// Showmessage
void Accountexp::Showmessage()
{
cout << "오류가 발생했습니다!" << endl;
}
/*입금 예외처리 클래스*/
// 생성자
Depositexp::Depositexp(int money):Accountexp(money){};
// Showmessage
void Depositexp::Showmessage() // 예외처리 메세지
{
cout << "1원 이상의 값을 재입력 하세요" << endl;
}
/*출금 에외처리 클래스*/
//생성자
Withdrawexp::Withdrawexp(int money):Accountexp(money){};
// Showmessage
void Withdrawexp::Showmessage() // 예외처리 메세지
{
cout << "잔액이 부족합니다. 값을 재입력하세요" << endl;
}
accounthandler.h
#include "accountarray.h"
#include "account.h"
#pragma once
/*Controller 클래스*/
class Accounthandler
{
private:
// 템플릿 클래스 호출, 객체(배열) acc 생성
Accountarray<ACCOUNT_PTR> acc;
int acc_count; // 고객 고유번호
public:
// 생성자
Accounthandler();
// 기능함수 선언(메뉴, 개설, 입금, 출금, 조회)
void Menu();
void Make();
void Deposit();
void Withdraw();
void Show();
};
accounthandler.cpp#include "accountarray.h"
#include "string.h"
#include "accounthandler.h"
#include <iostream>
#include "normal.h"
#include "high.h"
using namespace std;
#include "account.h"
#include "accountarray.cpp"
#include "exception.h"
/*about AccountHandler class*/
// 생성자
Accounthandler::Accounthandler()
:acc_count(0) // 고객번호는 0부터 시작(배열 인자 : 0 ~ )
{
}
// 기능함수
// 메뉴함수
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()
{
String id;
String name;
int balance;
int type;
// 계좌 개설 관련 신상정보 입력
cout << "계좌번호 : "; cin >> id;
cout << "성명 : "; cin >> name;
cout << "예치금 : "; cin >> balance;
cout << "[계좌유형 결정]" << endl;
cout << "(Normal=1/High=2) : "; cin >> type;
double rate;
char acc_level;
// 계좌 유형에 따라 다른 유형의 계좌 개설(동적할당)
switch (type)
{
case TYPE::NORMAL: // 노멀타입(1) 결정 시
{
cout << "이율 : "; cin >> rate; // 일반이율
// 배열인자 acc[i]의 동적할당(Normal class)
acc[acc_count++] = new Normal(id, name, balance, rate);
break;
}
case TYPE::HIGH: // 하이타입(2) 결정 시
{
cout << "이율 : "; cin >> rate; // 일반이율
cout << "고객등급 : "; cin >> acc_level; // 고객등급 입력 -> 특별이율 산출
// 배열인자 acc[i]의 동적할당(High class)
acc[acc_count++] = new High(id, name, balance, rate, acc_level);
}
}
}
// 입금함수
void Accounthandler::Deposit()
{
String id;
int money;
// 계좌번호 입력
cout << "계좌번호 입력 : "; cin >> id;
for (int i = 0; i < acc_count; i++) // 계좌번호 일치 조회
{
/*String클래스의 '=='연산자 오버로드 함수 호출*/
if (acc[i]->Get_id() == id) // 일치 시
{
while(1) // 올바른 값이 입력될 때 까지 금액 입력 요구(무한)
{
cout << "금액(만원) : "; cin >> money;
// 예외처리 try ~ throw ~ catch
try
{
if(money <=0)
{
throw Depositexp(money); // 예외를 객체(예외객체) 형태로 내보냄
}
break;
/* 예외가 없다면 break;를 실행하여 루프에서 벗어날 것이고 예외가 있다면 break레이블을 뛰어넘어
catch로 넘어오게 됨. 결과적으로 catch에서 에러메세지를 출력할 뿐 반복문에서 벗어나지 못한다.
*/
}
catch(Accountexp & dref)
// throw된 Depositexp객체를 상위클래스인 Accountexp형 매개변수로 받는다.
{
dref.Showmessage(); // Showmessage함수에 접근(virtual)
}
}
// 정상입금시 -> 입금함수 접근(virtual)
acc[i]->Proccess_depos(money);
cout << "정상 입금 되었습니다." << endl;
break;// for~문 탈출
}
// 현재까지 입력된 acc_count 끝까지 중 일치항목이 없을 시
else if (i == acc_count - 1)
cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
}
}
void Accounthandler::Withdraw()
{
// 입금함수의 과정과 동일
String id;
int money;
cout << "계좌번호 입력 : "; cin >> id;
for (int i = 0; i < acc_count; i++)
{
if (acc[i]->Get_id() == id) // 계좌번호 일치 확인
{
while(1) // 무한루프
{
cout << "금액(만원) : "; cin >> money;
// 예외처리 try ~ throw ~ catch
try
{
if(acc[i] -> Get_balance() < money) // 잔액이 출금액보다 적다면
{
throw Withdrawexp(money); // 예외객체 전달
}
break;
}
catch(Accountexp & wref) // 마찬가지 상위 클래스인 Accountexp를 매개변수형으로
{
wref.Showmessage();
}
}
acc[i]->Proccess_withdraw(money);
cout << "정상 출금 되었습니다." << endl;
}
else if (i == acc_count - 1)
cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
}
}
// 조회함수
void Accounthandler::Show()
{
cout << "------------------" << endl;;
for (int i = 0; i < acc_count; i++)
{
cout << acc[i];
/* 앞서 Accountclass 에서 정의한 friend ~형 '<<'연산자 오버로드 함수 호출
(public이기에 당연히 가능)
*/
}
}
main.cpp#include "account.h"
#include "accountarray.h"
#include "accounthandler.h"
#include "normal.h"
#include "high.h"
#include "string.h"
#include <iostream>
#include <cstring>
#include "accountarray.cpp"
int main()
{
Accounthandler AH; // controller 객체 생성
int choice;
while (1)
{
AH.Menu();
cout << "거래를 선택하세요 : "; cin >> choice;
switch (choice)
{
case MAKE:
{
AH.Make(); // controller객체의 기능함수(생성)호출
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;
}
}
while(1) // 올바른 옵션을 선택할 때까지 무한루프
{
char further[5];
cout << "거래를 계속 하시겠습니까?(yes / no) : "; cin >> further;
try
{
if(strcmp(further,"no")==0) // no입력 시 거래 종료
{
cout << "거래를 종료합니다." << endl;
return 0;
}
else if (strcmp(further, "yes")==0) // yes입력 시 계속
{
cout << "거래를 계속합니다." << endl;
break; // yes입력 시 옵션선택 무한루프 탈출
}
else // yes도 no도 아닌것이 입력될 시
{
throw 0; // 예외값 전달
}
}
catch(int number) // 예외값 catch
{
if(number == 0) // 예외 전달인자가 0일 시
{
cout << "다른옵션을 고르십시오" << endl;
// 에러메세지가 출력될 뿐, 옵션선택 루프에서 벗어나지 못한다.
}
}
}
}
return 0;
}
4.結果
4-2
4-3
4-4
4-5
5.カーテンコール
学習対象の特性とともに,独自のATM機能項目を構築しており,見応えがある.Cによるプログラミングでは,クラスを高C++で理解した.今度はJAVAの勉強の番ですね.
すべてのタスクはreplitで完了しました.
Reference
この問題について(C++. ATM Project ver.final), 我々は、より多くの情報をここで見つけました https://velog.io/@croco/ATM-Project-ver.finalテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol