버전 0.1 에서 만들었던 은행계좌 관리 프로그램을 버전 0.2 로 업그레이드 시켜보자.
구조체 Account 를 이번에 배운 클래스 Account 로 변경한다.
고민해봐야 할 두 가지
어떻게 캡슐화를 시키고 정보를 은닉시켜야 하는지.
생성자와 소멸자는 어떻게 정의해야 하는지.
두 가지 제약
버전 0.1 은 char형 배열을 멤버로 둬서 고객의 이름을 저장했는데, 버전 0.2 는 동적 할당의 형태로 구현하자.
(Account 클래스는 멤버변수로 문자열 포인터를 지니고 있어야 함)
객체 포인터 배열을 선언해서 객체를 저장해보자.
(버전 0.1 에서는 구조체 배열을 선언하였으니, 이를 포인터 배열로 변경해야 함)
#include <iostream>
#include <cstring>
using namespace std;
const int NAME_LEN = 20;
void ShowMenu(void); // 메뉴출력
void MakeAccount(void); // 계좌개설을 위한 함수
void DepositMoney(void); // 입 금
void WithdrawMoney(void); // 출 금
void ShowAllAccInfo(void); // 잔액조회
enum { MAKE = 1, DEPOSIT, WITHDRAW, INQUIRE, EXIT };
class Account
{
private:
int accID; // 계좌번호
int balance; // 잔 액
char* cusName; // 고객이름
public:
Account(int ID, int money, char* name)
: accID(ID), balance(money)
{
cusName = new char[strlen(name) + 1];
strcpy(cusName, name);
}
int GetAccID() { return accID; }
void Deposit(int money)
{
balance += money;
}
int Withdraw(int money) // 출금액 반환, 부족 시 0
{
if (balance < money)
return 0;
balance -= money;
return money;
}
void ShowAccInfo()
{
cout << "계좌ID: " << accID << endl;
cout << "이 름: " << cusName << endl;
cout << "잔 액: " << balance << endl;
}
~Account()
{
delete[]cusName;
}
};
Account* accArr[100]; // Account 저장을 위한 배열
int accNum = 0; // 저장된 Account 수
int main(void)
{
int choice;
while (1)
{
ShowMenu();
cout << "선택: ";
cin >> choice;
cout << endl;
switch (choice)
{
case MAKE:
MakeAccount();
break;
case DEPOSIT:
DepositMoney();
break;
case WITHDRAW:
WithdrawMoney();
break;
case INQUIRE:
ShowAllAccInfo();
break;
case EXIT:
return 0;
default:
cout << "Illegal selection.." << endl;
}
}
for (int i = 0; i < accNum; i++)
delete accArr[i];
return 0;
}
void ShowMenu(void)
{
cout << "-----Menu------" << endl;
cout << "1. 계좌개설" << endl;
cout << "2. 입 금" << endl;
cout << "3. 출 금" << endl;
cout << "4. 계좌정보 전체 출력" << endl;
cout << "5. 프로그램 종료" << endl;
}
void MakeAccount(void)
{
int id;
char name[NAME_LEN];
int balance;
cout << "[계좌개설]" << endl;
cout << "계좌ID: "; cin >> id;
cout << "이 름: "; cin >> name;
cout << "입금액: "; cin >> balance;
cout << endl;
accArr[accNum++] = new Account(id, balance, name);
}
void DepositMoney(void)
{
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 WithdrawMoney(void)
{
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 ShowAllAccInfo(void)
{
for (int i = 0; i < accNum; i++)
{
accArr[i]->ShowAccInfo();
cout << endl;
}
}
내가 겪은 시행착오
private 하고있는 accID에 접근하려다가 오류 발생
-> Account 클래스 내부에 GetAccId 함수를 만들고 GetAccId 함수를 통해서 accID 를 리턴값으로 받아내서 해결함. (136 줄)
~Account() 소멸자 생성해서 동적할당 했던 멤버변수 cusName 은 없앴지만 클래스 포인터배열 Account *accArr[100] 을 없애는 생각을 못했다. (95줄)
if(accArr[i]->Withdraw(money) == 0) 에서 40줄 에서 return 0 을 반환 시켜두고 < 0 으로 써서 가지고 있는 돈 보다 더 많은 돈을 출금 시켰을때 정상적으로 출금이 됐다.
따로 오류 코드가 안떠서 그냥 넘어갈 뻔했다. (158 줄)
calss 내부 함수에 접근할때 관련 모든 코드를 . 으로 접근시켜서 오류가 대량 발생했다
. 은 class 의 멤버를 직접 접근한다.
->은 포인터를 통해 멤버를 접근한다.
Account * accArr[100]; Account 저장을 위한 포인터 배열을 만들었고 (59 줄)
accArr[accNum++] = new Account(id, balance, name); 그 포인터 배열을 이용하여 new 연산자를 통해 동적할당을 했다 (123 줄)
그러므로 . 으로 접근하는 방식이 아닌 -> 를 사용해야 한다.