C++/열혈 C++ 프로그래밍(윤성우 저)

OOP 단계별 프로젝트 9

꾸준함. 2017. 6. 13. 22:21

[Account.h]

/*

우리가 정의한 Account 클래스는 생성자에서 문자열을 동적 할당하기 때문에, 소멸자 그리고 깊은 복사를 위한

복사생성자와 대입 연산자가 정의되어 있다.

그런데 이번에 적용할 String 클래스는 메모리 공간을 동적 할당하고, 깊은 복사를 진행하는 형태로 복사생성자와 대입

연산자가 정의되어 있기 때문에, 이를 이용하면 Account 클래스의 구현이 한결 간단해진다.

조금 더 자세히 설명하면, Account 클래스의 생성자 내에서의 동적 할당이 불필요해지며,

이로 인해서 직접 정의한 소멸자와 복사 생성자 그리고 대입 연산자가 모두 불필요해진다.

바로 이러한 사실을 확인하고 다음의 결론을 스스로 내리는 것이 이번 프로젝트의 핵심이라 할 수 있다.

"적절한 클래스의 등장은 다른 클래스의 정의를 간결하게 해준다"

참고로 String 클래스를 등장시켰다고 해서 char형 포인터 기반의 문자열 표현을 억지로 제한할 필요는 없다.

그러나 본 프로젝트의 목적 중 하나는 직접 정의한 클래스를 적용하는데 있으니, 가급적 String 객체를 이용해서 문자열을 표현하기로 하자.

마지막으로 실제 변경이 발생하는 헤더파일과 소스파일은 다음과 같다.

Account.h, Account.cpp

NormalAccount.h

HighCreditAccount.h

AccountHandler.cpp

그리고 String 클래스의 추가를 위해서 다음의 소스파일과 헤더파일을 추가하였다.

String.h, String.cpp->String 클래스의 선언과 정의

*/

 

#ifndef __ACCOUNT_H__

#define __ACCOUNT_H__

 

#include "String.h"

 

//Entity 클래스

class BankAccount

{

private:

        int AccountNumber; //계좌 번호

        /*

        char *Name; //고객 이름

        */

        String Name;

        int Money; //고객의 잔액

public:

        //BankAccount(int num, char *name, int money);

        BankAccount(int num, String name, int money);

        //BankAccount(const BankAccount &copy);

        //BankAccount &operator=(const BankAccount &ref); //추가된 문장

 

        int GetNumber() const;

        virtual void Deposit(int money);

        int Withdraw(int money);

        void ShowAccountInfo() const;

        //~BankAccount();

};

 

#endif

 

[Account.cpp]

#include "BankingCommonDecl.h"

#include "Account.h"

 

/*

BankAccount::BankAccount(int num, char *name, int money) :AccountNumber(num), Money(money)

{

        Name = new char[strlen(name) + 1];

        strcpy(Name, name);

}

*/

BankAccount::BankAccount(int num, String name, int money) :AccountNumber(num), Money(money)

{

        Name = name;

}

 

/*

BankAccount::BankAccount(const BankAccount &copy) :AccountNumber(copy.AccountNumber), Money(copy.Money)

{

        Name = new char[strlen(copy.Name) + 1];

        strcpy(Name, copy.Name);

}

 

BankAccount &BankAccount::operator=(const BankAccount &ref) //이번에 추가

{

        AccountNumber = ref.AccountNumber;

        Money = ref.Money;

 

        delete[]Name; //메모리 누수 방지

        Name = new char[strlen(ref.Name) + 1];

        strcpy(Name, ref.Name);

        return *this;

}

*/

 

int BankAccount::GetNumber() const

{

        return AccountNumber;

}

 

void BankAccount::Deposit(int money)

{

        //printf("%d원이 입금되었습니다\n", money); //제대로 동작하나 확인

        Money += money;

}

 

int BankAccount::Withdraw(int money)

{

        if (Money < money)

               return 0;

 

        Money -= money;

        return money;

}

 

void BankAccount::ShowAccountInfo() const

{

        cout << "이름:" << Name << endl;

        cout << "계좌번호:" << AccountNumber << endl;

        cout << "잔고:" << Money << endl;

}

 

/*

BankAccount::~BankAccount()

{

        delete[]Name;

}

*/


[AccountArray.h]

#ifndef __ACCOUNT_ARRAY_H__

#define __ACCOUNT_ARRAY_H__

 

#include "Account.h"

typedef BankAccount *BANKACCOUNT_PTR; //포인터 typedef

 

class BoundCheckAccountPtrArray

{

private:

        BoundCheckAccountPtrArray &operator=(const BoundCheckAccountPtrArray &arr) //복사 원천적으로 막음

        {

        }

public:

        BoundCheckAccountPtrArray(int len = 100);

        BANKACCOUNT_PTR *arr;

        int arrlen;

        BoundCheckAccountPtrArray(const BoundCheckAccountPtrArray &arr) //대입 원천적으로 막음

        {

        }

        BANKACCOUNT_PTR &operator[](int idx);

        BANKACCOUNT_PTR operator[](int idx) const; //const 대상의 오버로딩

        int GetArrLen() const;

        ~BoundCheckAccountPtrArray();

};

 

#endif

 

[AccountArray.cpp]

#include "BankingCommonDecl.h"

#include "AccountArray.h"

 

BoundCheckAccountPtrArray::BoundCheckAccountPtrArray(int len) :arrlen(len)

{

        arr = new BANKACCOUNT_PTR[len];

}

 

BANKACCOUNT_PTR &BoundCheckAccountPtrArray::operator[](int idx)

{

        if (idx < 0 || idx >= arrlen)

        {

               cout << "Array index out of bound exception" << endl;

               exit(1);

        }

        return arr[idx];

}

 

BANKACCOUNT_PTR BoundCheckAccountPtrArray::operator[](int idx) const

{

        if (idx < 0 || idx >= arrlen)

        {

               cout << "Array index out of bound exception" << endl;

               exit(1);

        }

        return arr[idx];

}

 

int BoundCheckAccountPtrArray::GetArrLen() const

{

        return arrlen;

}

 

BoundCheckAccountPtrArray::~BoundCheckAccountPtrArray()

{

        delete[]arr;

}


[String.h]

#ifndef __STRING_H__

#define __STRING_H__

 

#include "BankingCommonDecl.h"

 

class String

{

private:

        int len;

        char *str;

public:

        String();

        String(const char *s);

        String(const String &s);

        ~String();

        String &operator=(const String &s);

        String &operator+=(const String &s);

        bool operator==(const String &s);

        String operator+(const String &s);

 

        friend ostream &operator<<(ostream &os, const String &s);

        friend istream &operator>>(istream &is, String &s);

};

 

#endif

 

[String.cpp]

#include "String.h"

 

String::String()

{

        len = 0;

        str = NULL;

}

 

String::String(const char *s)

{

        len = strlen(s) + 1;

        str = new char[len];

        strcpy(str, s);

}

 

String::String(const String &s)

{

        len = s.len;

        str = new char[len];

        strcpy(str, s.str);

}

 

String::~String()

{

        if (str != NULL)

               delete[]str;

}

 

String &String::operator=(const String &s)

{

        if (str != NULL)

               delete[]str;

        len = s.len;

        str = new char[len];

        strcpy(str, s.str);

        return *this;

}

 

String &String::operator+=(const String &s)

{

        len += (s.len - 1);

        char *tempstr = new char[len];

        strcpy(tempstr, str);

        strcat(tempstr, s.str);

 

        if (str != NULL)

               delete[]str;

        str = tempstr;

        return *this;

}

 

bool String::operator==(const String &s)

{

        return strcmp(str, s.str) ? false : true;

}

 

String String::operator+(const String &s)

{

        char *tempstr = new char[len + s.len - 1];

        strcpy(tempstr, str);

        strcat(tempstr, s.str);

 

        String temp(tempstr);

        delete[]tempstr;

        return temp;

}

 

ostream &operator<<(ostream &os, const String &s)

{

        os << s.str;

        return os;

}

 

istream &operator>>(istream &is, String &s)

{

        char str[100];

        is >> str;

        s = String(str);

        return is;

}


[NormalAccount.h]

#ifndef __NORMAL_ACCOUNT_H__

#define __NORMAL_ACCOUNT_H__

 

#include "Account.h"

#include "String.h"

 

//노말

class NormalAccount :public BankAccount

{

private:

        int ratio;

public:

        /*

        NormalAccount(int num, char *name, int money, int profits) :BankAccount(num, name, money), ratio(profits)

        {

        }

        */

        NormalAccount(int num, String name, int money, int profits) :BankAccount(num, name, money), ratio(profits)

        {

        }

        virtual void Deposit(int money)

        {

               BankAccount::Deposit(money); //원금

               BankAccount::Deposit(money*(ratio / 100.0)); //이자

        }

};

 

#endif


[HighCreditAccount.h]

#ifndef __HIGHCREDIT_ACCOUNT_H__

#define __HIGHCREDIT_ACCOUNT_H__

 

#include "NormalAccount.h"

#include "String.h"

 

//신용

class HighCreditAccount :public NormalAccount

{

private:

        int credit;

public:

        /*

        HighCreditAccount(int num, char *name, int money, int profits, int credibility) :NormalAccount(num, name, money, profits), credit(credibility)

        {

        }

        */

        HighCreditAccount(int num, String name, int money, int profits, int credibility) :NormalAccount(num, name, money, profits), credit(credibility)

        {

        }

        virtual void Deposit(int money)

        {

               NormalAccount::Deposit(money); //원금 이자

               BankAccount::Deposit(money*(credit / 100.0)); //추가이자

        }

};

 

#endif


[AccountHandler.h]

#ifndef __ACCOUNT_HANDLER_H__

#define __ACCOUNT_HANDLER_H__

 

#include "Account.h"

#include "AccountArray.h"

 

//컨트롤 클래스

class AccountHandler

{

private:

        /*

        BankAccount *Arr[10]; //계좌 포인터 배열

        */

        BoundCheckAccountPtrArray Arr; //이번에 추가

        int AccountNum; //계좌 개수

public:

        AccountHandler();

        ~AccountHandler();

        int Menu(void); //메뉴

        void MakeBankAccount(void); //계좌 개설

        void Deposit(int money); //입금

        void Withdraw(int money); //출금

        void ShowAccountInfo(void); //전체고객 잔액조회

private: //이 부분은 책을 참고, protected는 외부에서 보면 private, 상속관계에서 보면 public!

        void MakeNormalAccount(void);

        void MakeCreditAccount(void);

};

 

#endif


[AccountHandler.cpp]

#include "BankingCommonDecl.h"

#include "AccountHandler.h"

#include "Account.h"

#include "NormalAccount.h"

#include "HighCreditAccount.h"

#include "String.h"

 

AccountHandler::AccountHandler() :AccountNum(0)

{

}

 

AccountHandler::~AccountHandler()

{

        for (int i = 0; i < AccountNum; i++)

               delete Arr[i];

}

 

int AccountHandler::Menu(void)

{

        int sel;

        cout << "-----Menu-----" << endl;

        cout << "1.계좌개설" << endl << "2.입금" << endl << "3.출금" << endl << "4.계좌정보 전체 출력" << endl << "5.프로그램 종료" << endl;

        cout << "선택";

        cin >> sel;

        return sel;

}

 

void AccountHandler::MakeBankAccount()

{

        int sel;

        cout << "계좌 종류를 선택하시오" << endl;

        cout << "1.보통계좌\t2.신용계좌:";

        cin >> sel;

 

        if (sel == 1)

               MakeNormalAccount();

        else if (sel == 2)

               MakeCreditAccount();

        else

        {

               while (sel == 1 || sel == 2)

               {

                       cout << "번호를 잘못 선택하셨습니다 다시 선택하세요";

                       cin >> sel;

                       if (sel == 1)

                              MakeNormalAccount();

                       else if (sel == 2)

                              MakeCreditAccount();

               }

        }

}

 

void AccountHandler::MakeNormalAccount(void)

{

        int accountNumber;

        //char name[30];

        String name;

        int money;

        int ratio;

        cout << AccountNum + 1 << "번째 사람 정보 입력" << endl;

        cout << "계좌번호 입력:";

        cin >> accountNumber;

        cout << "이름 입력:";

        cin >> name;

        cout << "잔액 입력:";

        cin >> money;

        cout << "이율 입력:";

        cin >> ratio;

        cout << endl;

 

        Arr[AccountNum++] = new NormalAccount(accountNumber, name, money, ratio); //계좌개설 완료 후 다음 사람으로

}

 

void AccountHandler::MakeCreditAccount(void)

{

        int accountNumber;

        //char name[30];

        String name;

        int money;

        int ratio;

        int rank;

        cout << AccountNum + 1 << "번째 사람 정보 입력" << endl;

        cout << "계좌번호 입력:";

        cin >> accountNumber;

        cout << "이름 입력:";

        cin >> name;

        cout << "잔액 입력:";

        cin >> money;

        cout << "이율 입력:";

        cin >> ratio;

        cout << "신용등급(1.RankA, 2.RankB, 3.RankC) 입력:";

        cin >> rank;

        cout << endl;

 

        switch (rank)

        {

        case 1:

               Arr[AccountNum++] = new HighCreditAccount(accountNumber, name, money, ratio, RankA);

               break;

        case 2:

               Arr[AccountNum++] = new HighCreditAccount(accountNumber, name, money, ratio, RankB);

               break;

        case 3:

               Arr[AccountNum++] = new HighCreditAccount(accountNumber, name, money, ratio, RankC);

               break;

        }

}

 

void AccountHandler::Deposit(int money)

{

        int number;

        cout << "고객님의 계좌번호를 입력해주세요:";

        cin >> number;

        for (int i = 0; i <= AccountNum; i++)

        {

               if (Arr[i]->GetNumber() == number) //계좌번호가 같으면

               {

                       Arr[i]->Deposit(money);

                       cout << "입금이 완료되었습니다" << endl;

                       return;

               }

        }

        cout << "없는 계좌번호입니다" << endl;

}

 

void AccountHandler::Withdraw(int money)

{

        int number;

        cout << "고객님의 계좌번호를 입력해주세요:";

        cin >> number;

        for (int i = 0; i <= AccountNum; i++)

        {

               if (Arr[i]->GetNumber() == number) //계좌번호가 같으면

               {

                       if (Arr[i]->Withdraw(money) == 0)

                       {

                              cout << "잔액이 부족합니다" << endl;

                              return;

                       }

                       cout << "출금이 완료되었습니다" << endl;

                       return;

               }

        }

        cout << "없는 계좌번호입니다" << endl;

}

 

void AccountHandler::ShowAccountInfo(void)

{

        for (int i = 0; i < AccountNum; i++)

        {

               Arr[i]->ShowAccountInfo();

               cout << endl;

        }

}


[BankingSystemMain.cpp]

#include "BankingCommonDecl.h"

#include "AccountHandler.h"

 

int main(void)

{

        AccountHandler handler;

        int money;

        while (1)

        {

               int sel = handler.Menu();

               switch (sel)

               {

               case 1:

                       handler.MakeBankAccount();

                       break;

               case 2:

                       cout << "입금할 금액:";

                       cin >> money;

                       handler.Deposit(money);

                       break;

               case 3:

                       cout << "출금할 금액:";

                       cin >> money;

                       handler.Withdraw(money);

                       break;

               case 4:

                       handler.ShowAccountInfo();

                       break;

               case 5:

                       return 0;

               default:

                       cout << "잘못된 번호를 입력하셨습니다" << endl;

               }

        }

        return 0;

}



개발 환경:Visual Studio 2017


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~


[참고] 열혈 C++ 프로그래밍 윤성우 저

반응형