버전 0.5 에서 만들었던 은행계좌 관리 프로그램을 버전 0.6 으로 업그레이드 시켜보자.
이전에 정의한 Account 클래스를 상속하는 다음 두 클래스를 추가로 정의하고자 한다.
앞서 정의한 Account 클래스는 이자와 관련된 내용이 없다.
그런데 일반 사용자가 이용하는 예금에는 적게나마 이자가 지급이 되니, 이자의 지급 및 처리방식에 따라서 위의 두 클래스를 추가로 정의하고자 한다
위에서 말하는 '보통예금계좌' 는 우리가 흔히 사용하는, 최소한의 이자를 지급하는 자율 입출금식 계좌이다.
반면 '신용신뢰계좌' 는 신용도가 높은 고객에게만 개설을 허용하는 높은 이율의 계좌를 의미한다.
'보통예금계좌' 를 의미하는 NormalAccount 클래스
'신용신뢰계좌' 를 의미하는 HighCreditAccount 클래스
사실 이자는 시간이 지나야 발생하지만, 우리는 구현의 편의상 입금 시에 이자가 원금에 더해지는 것으로 간주한다.
그리고 모든 계좌에 대해 공히 다음의 조건을 적용하자.
그리고 컨트롤 클래스인 AccountHandler 클래스에는 큰 변화가 없어야 한다.
단, 계좌의 종류가 늘어난 만큼 메뉴의 선택과 데이터의 입력과정에서의 불가피한 변경을 허용을 한다.
#include <iostream>
#include <cstring>
using namespace std;
const int NAME_LEN = 20;
enum {MAKE=1, DEPOSIT, WITHDRAW, INQUIRE, EXIT};
enum { LEVEL_A = 7, LEVEL_B = 4, LEVEL_C = 2 };
enum {NORMAL=1, CREDIT=2};
class Account {
int accID;
int balance;
char* cusName;
public:
Account(int id, int money, char* name);
Account(const Account& ref);
int GetAccID() const;
virtual void Deposit(int money);
int Withdraw(int money);
void ShowAccInfo() const;
~Account();
};
Account::Account(int id, int money, char* name)
:accID(id), balance(money) {
cusName = new char[strlen(name) + 1];
strcpy(cusName, name);
}
Account::Account(const Account& ref)
: accID(ref.accID), balance(ref.balance) {
cusName = new char[strlen(ref.cusName) + 1];
strcpy(cusName, ref.cusName);
}
int Account::GetAccID() const { return accID; }
void Account::Deposit(int money) {
balance += money;
}
int Account::Withdraw(int money) {
if (balance < money)
return 0;
balance -= money;
return money;
}
void Account::ShowAccInfo() const {
cout << "계좌ID: " << accID << endl;
cout << "이 름: " << cusName << endl;
cout << "잔 액: " << balance << endl;
}
Account::~Account() {
delete[]cusName;
}
class NormalAccount : public Account {
int interRate;
public:
NormalAccount(int id, int money, char*name, int rate)
:Account(id, money, name), interRate(rate)
{}
virtual void Deposit(int money) {
Account::Deposit(money);
Account::Deposit(money * (interRate / 100.0));
}
};
class HighCreditAccount : public NormalAccount {
int specialRate;
public:
HighCreditAccount(int id, int money, char* name, int rate, int special)
:NormalAccount(id, money, name, rate), specialRate(special)
{}
virtual void Deposit(int money) {
NormalAccount::Deposit(money);
Account::Deposit(money * (specialRate / 100.0));
}
};
class AccountHandler {
Account* accArr[100];
int accNum;
public:
AccountHandler();
void ShowMenu() const;
void MakeAccount();
void DepositMoney();
void WithdrawMoney();
void ShowAllAccInfo() const;
~AccountHandler();
protected:
void MakeNormalAccount();
void MakeCreditAccount();
};
AccountHandler::AccountHandler() : accNum(0) {}
void AccountHandler::ShowMenu() const {
cout << "-----Menu-----" << endl;
cout << "1. 계좌개설" << endl;
cout << "2. 입 금" << endl;
cout << "3. 출 금" << endl;
cout << "4. 계좌정보 전체 출력" << endl;
cout << "5. 프로그램 종료" << endl;
}
void AccountHandler::MakeAccount() {
int input;
cout << "[계좌종류선택]" << endl;
cout << "1. 보통예금계좌 2. 신용신뢰계좌 " << endl;
cout << "선택: ";
cin >> input;
if (input == NORMAL)
MakeNormalAccount();
else
MakeCreditAccount();
}
void AccountHandler::MakeNormalAccount() {
int id;
char name[NAME_LEN];
int balance;
int interRate;
cout << "[보통예금계좌 개설]" << endl;
cout << "계좌ID: "; cin >> id;
cout << "이 름: "; cin >> name;
cout << "입금액: "; cin >> balance;
cout << "이자율: "; cin >> interRate;
cout << endl;
accArr[accNum++] = new NormalAccount(id, balance, name, interRate);
}
void AccountHandler::MakeCreditAccount() {
int id;
char name[NAME_LEN];
int balance;
int interRate;
int creditLevel;
cout << "[신용신뢰계좌 개설]" << endl;
cout << "계좌ID: "; cin >> id;
cout << "이 름: "; cin >> name;
cout << "입금액: "; cin >> balance;
cout << "이자율: "; cin >> interRate;
cout << "신용등급(1toA, 2toB, 3toC): "; cin >> creditLevel;
cout << endl;
switch (creditLevel) {
case 1:
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, LEVEL_A);
break;
case 2:
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, LEVEL_B);
break;
case 3:
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, LEVEL_C);
break;
}
}
void AccountHandler::DepositMoney() {
int money;
int id;
cout << "[입 금]" << endl;
cout << "계좌ID: "; cin >> id;
cout << "입금액: "; cin >> money;
for (int i = 0; i < accNum; i++) {
if (accArr[i]->GetAccID() == id) {
accArr[i]->Deposit(money);
cout << "입금완료" << endl << endl;
return;
}
}
cout << "유효하지 않은 ID 입니다." << endl << endl;
}
void AccountHandler::WithdrawMoney() {
int money;
int id;
cout << "[출 금]" << endl;
cout << "계좌ID: "; cin >> id;
cout << "출금액: "; cin >> money;
for (int i = 0; i < accNum; i++) {
if (accArr[i]->GetAccID() == id) {
if (accArr[i]->Withdraw(money) == 0) {
cout << "잔액부족" << endl << endl;
return;
}
cout << "출금완료" << endl << endl;
return;
}
}
cout << "유효하지 않은 ID 입니다." << endl << endl;
}
void AccountHandler::ShowAllAccInfo() const {
for (int i = 0; i < accNum; i++) {
accArr[i]->ShowAccInfo();
cout << endl;
}
}
AccountHandler::~AccountHandler() {
for (int i = 0; i < accNum; i++)
delete accArr[i];
}
int main()
{
AccountHandler manager;
int choice;
while (1) {
manager.ShowMenu();
cout << "선택: ";
cin >> choice;
cout << endl;
switch (choice) {
case MAKE:
manager.MakeAccount();
break;
case DEPOSIT:
manager.DepositMoney();
break;
case WITHDRAW:
manager.WithdrawMoney();
break;
case INQUIRE:
manager.ShowAllAccInfo();
break;
case EXIT:
return 0;
default:
cout << "다시 입력해주세요." << endl;
}
}
return 0;
}
21행 void Deposit(int money); 선언에 virtual 키워드를 붙임으로써
68행, 82행 에도 virtual 이 붙게되고 (생략 가능, 명시적으로 표시해서 가독성 up)
180행 accArr[i]->Deposit(money); 에서 accArr[i] 가 가리키는 주소에 Deposit(money) 가 실행되면서 오류를 해결됐다.
8행, 9행 enum 을 추가해서 가독성을 더 좋게 만들었다.
70행, 84행 이자 계산을 하는 부분에서 100.0 을 100 으로 넣어서 한동안 어떤게 문제인지 해결을 못했다.
100을 넣고 실행시키면 제대로 이자를 계산해서 넣지 못한다.
이유는 specialRate, 100 둘다 int형 이기 때문이다.
specialRate = 10 이라고 가정했을때 10/100 = 0.1 이다. 하지만 int형으로 계산하기 때문에 0이 되는것이고 그래서 이자가 0으로 나온다.