[C++] 윤성우 열혈 - OOP 단계별 프로젝트 06단계 (상속과 다향성)

Kim Dongil·2022년 12월 11일
0

C++

목록 보기
10/23

버전 0.5 에서 만들었던 은행계좌 관리 프로그램을 버전 0.6 으로 업그레이드 시켜보자.

프로젝트 06단계의 도입

이전에 정의한 Account 클래스를 상속하는 다음 두 클래스를 추가로 정의하고자 한다.

  • NormalAccount 보통예금계좌
  • HighCreditAccount 신용신뢰계좌

앞서 정의한 Account 클래스는 이자와 관련된 내용이 없다.
그런데 일반 사용자가 이용하는 예금에는 적게나마 이자가 지급이 되니, 이자의 지급 및 처리방식에 따라서 위의 두 클래스를 추가로 정의하고자 한다

위에서 말하는 '보통예금계좌' 는 우리가 흔히 사용하는, 최소한의 이자를 지급하는 자율 입출금식 계좌이다.
반면 '신용신뢰계좌' 는 신용도가 높은 고객에게만 개설을 허용하는 높은 이율의 계좌를 의미한다.

프로그램 설명

'보통예금계좌' 를 의미하는 NormalAccount 클래스

  • 객체의 생성과정에서 이율정보를 등록할 수 있도록 정의하자.

'신용신뢰계좌' 를 의미하는 HighCreditAccount 클래스

  • NormalAccount 클래스와 마찬가지로 객체 생성과정에서 기본이율을 등록 할수 있다.
  • 고객의 신용등급을 A, B, C 로 나누고 계좌개설 시 이 정보를 등록한다.
  • A, B, C 등급별로 각각 기본이율에 7%, 4%, 2% 이율을 추가로 제공한다.

사실 이자는 시간이 지나야 발생하지만, 우리는 구현의 편의상 입금 시에 이자가 원금에 더해지는 것으로 간주한다.
그리고 모든 계좌에 대해 공히 다음의 조건을 적용하자.

  • 계좌개설 과정에서 초기 입금되는 금액에 대해서는 이자를 계산하지 않는다.
  • 계좌개설 후 별도의 입금과정을 거칠 때에만 이자가 발생하는 것으로 간주한다.
  • 이자의 계산과정에서 발생하는 소수점 이하의 금액은 무시한다.

그리고 컨트롤 클래스인 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;
}
  1. virtual 키워드를 안넣어서 오류가 떴다.

21행 void Deposit(int money); 선언에 virtual 키워드를 붙임으로써
68행, 82행 에도 virtual 이 붙게되고 (생략 가능, 명시적으로 표시해서 가독성 up)
180행 accArr[i]->Deposit(money); 에서 accArr[i] 가 가리키는 주소에 Deposit(money) 가 실행되면서 오류를 해결됐다.

  1. 8행, 9행 enum 을 추가해서 가독성을 더 좋게 만들었다.

  2. 70행, 84행 이자 계산을 하는 부분에서 100.0 을 100 으로 넣어서 한동안 어떤게 문제인지 해결을 못했다.

100을 넣고 실행시키면 제대로 이자를 계산해서 넣지 못한다.
이유는 specialRate, 100 둘다 int형 이기 때문이다.
specialRate = 10 이라고 가정했을때 10/100 = 0.1 이다. 하지만 int형으로 계산하기 때문에 0이 되는것이고 그래서 이자가 0으로 나온다.

0개의 댓글

관련 채용 정보