버전 0.8 에서 만들었던 은행계좌 관리 프로그램을 버전 0.9 로 업그레이드 시켜보자.
경험이 부족하면, 자신이 정의한 클래스를 프로그램 전체에 적절히 적용하는데 어려움을 느낄 수 있다.
따라서 클래스를 정의하는 것만큼은 아니지만, 자신이 정의한 클래스를 활용하는 데도 연습이 필요하다.
이에 앞서 예제 StringClass.cpp 를 통해서 우리가 정의한 String 클래스를 단계별 프로젝트에 적용해보고자 한다.
우리가 정의한 Account 클래스는 생성자에서 문자열을 동적 할당하기 때문에, 소멸자 그리고 깊은 복사를 위한 복사 생성자와 대입 연산자가 정의되어 있다.
그런데 이번에 적용할 String 클래스는 메모리 공간을 동적 할당하고, 깊은 복사를 진행하는 형태로 복사 생성자와 대입 연산자가 정의되어 있기 때문에, 이를 이용하면 Account 클래스의 구현이 한결 간단해진다.
조금 더 자세히 설명하면, Account 클래스의 생성자 내에서의 동적 할당이 불필요해지며, 이로 인해서 직접 정의한 소멸자와 복사 생성자 그리고 대입 연산자가 모두 불필요해진다.
바로 이러한 사실을 확인하고 다음의 결론을 스스로 내리는 것이 이번 프로젝트의 핵심이라 할 수 있다.
"적절한 클래스의 등장은 다른 클래스의 정의를 간결하게 해 준다."
참고로 String 클래스를 등장시켰다고 해서 char형 포인터 기반의 문자열 표현을 억지로 제한할 필요는 없다.
그러나 본 프로젝트의 목적 중 하나는 직접 정의한 클래스를 적용하는데 있으니, 가급적 String 객체를 잉요해서 문자열을 표현하기로 하자.
마지막으로 실제 변경입 발생하는 헤더파일과 소스파일은 다음과 같다.
그리고 String 클래스의 추가를 위해서 다음의 소스파일과 헤더파일을 추가하였다.
Account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include "String.h"
class Account {
int accID;
int balance;
String cusName; // ------- 변경
public:
Account(int id, int money, String name);
// ------ 복사, 대입, 소멸자 삭제
int GetAccID() const;
virtual void Deposit(int money);
int Withdraw(int money);
void ShowAccInfo() const;
};
#endif
Account.cpp
#include "BankingCommonDecl.h"
#include "Account.h"
Account::Account(int id, int money, String name) // -------- 변경
:accID(id), balance(money), cusName(name) {}
//------ 복사, 대입, 소멸자 삭제
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;
}
NormalAccount.h
#ifndef __NORMAL_ACCOUNT_H__
#define __NORMAL_ACCOUNT_H__
#include "Account.h"
class NormalAccount : public Account {
int interRate;
public:
NormalAccount(int id, int money, String name, int rate) // -------- 변경
:Account(id, money, name), interRate(rate)
{}
virtual void Deposit(int money) {
Account::Deposit(money);
Account::Deposit(money * (interRate / 100.0));
}
};
#endif
HighCreditAccount.h
#ifndef __HIGHCREDIT_ACCOUNT_H__
#define __HIGHCREDIT_ACCOUNT_H__
#include "NormalAccount.h"
class HighCreditAccount : public NormalAccount {
int specialRate;
public:
HighCreditAccount(int id, int money, String 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));
}
};
#endif
AccountHandler.cpp
#include "BankingCommonDecl.h"
#include "AccountHandler.h"
#include "Account.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"
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;
String name; //-------- 변경
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;
String name; // -------- 변경
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];
}
String.h
#ifndef __STRING_H__ // ------------- 헤더파일 추가
#define __STRING_H__
#include "BankingCommonDecl.h"
using namespace std;
class String {
char* str;
int len;
public:
String(); // 생성자
String(const char* _str); // 생성자
String(const String& ref); // 복사 생성자
~String(); // 소멸자
String& operator=(const String& ref); // 대입 연산자
String operator+(const String& ref); // + 연산자
String& operator+=(const String& ref); // += 연산자
bool operator==(const String& ref); // == 연산자
friend ostream& operator<<(ostream& os, const String& ref); // << 연산자
friend istream& operator>>(istream& is, String& ref); // >> 연산자
};
#endif;
String.cpp
#include "String.h" // ------------- 소스파일 추가
String::String() { // 생성자
len = 0;
str = NULL;
}
String::String(const char* _str) { // 생성자
len = strlen(_str) + 1;
str = new char[len];
strcpy(str, _str);
}
String::String(const String& ref) { // 복사 생성자
len = ref.len;
str = new char[len];
strcpy(str, ref.str);
}
String& String::operator=(const String& ref) { // 대입 연산자
if (str != NULL)
delete[]str;
len = ref.len;
str = new char[len];
strcpy(str, ref.str);
return *this;
}
String String::operator+(const String& ref) { // + 연산자
char* tempstr = new char[len + ref.len - 1];
strcpy(tempstr, str);
strcat(tempstr, ref.str);
String temp(tempstr);
delete[]tempstr;
return temp;
}
String& String::operator+=(const String& ref) { // += 연산자
len += (ref.len - 1);
char* tempstr = new char[len];
strcpy(tempstr, str);
strcat(tempstr, ref.str);
if (str != NULL)
delete[]str;
str = tempstr;
return *this;
}
bool String::operator==(const String& ref) { // == 연산자
return strcmp(str, ref.str) ? false : true;
}
String::~String() {
if (str != NULL)
delete[]str;
}
ostream& operator<<(ostream& os, const String& ref) { // << 연산자
os << ref.str;
return os;
}
istream& operator>>(istream& is, String& ref) { // >> 연산자
char str[100];
is >> str;
ref = String(str);
return is;
}
이외 파일 변경 x