C++. ATM Project ver.5

lsw·2021년 4월 8일
0

Mini Projects

목록 보기
5/11
post-thumbnail

1. 업데이트

Updated as follows

  • Declare and define array class and adopt it in "accounthandler" class to substitute member variable "Account * arr[]" for the use of..
  1. 배열클래스는 배열의 동적할당 의무를 대신해 주기에 컨트롤러 클래스를 보다 간소히 정의할 수 있음
  2. 조회에 해당하는 함수를 배열 클래스 멤버내 연산자("<<")오버로드 함수로 대체함(기존 함수 폐기)
  3. 배열 관련 연산자 오버로드가 필요할 때 생성해둔 배열클래스를 이용하면 컨트롤러 클래스를 좀 더 간소화할 수 있음.

2. 코드

  • segmented into 6 'header files' and 7 'source files'

Header files - Declaration

  1. string.h
  • "문자열 관련 잡무를 대신해 주는 클래스"
#pragma once // 다중 참조 방지
#include<iostream>
using namespace std;

class String
{
	int len;
	char* str;

public:
	String(); // 디폴트 생성자
	String(const char* Str); // 주소를 인자로 갖는 생성자
	String(const String& scopy); // 복사생성자
	String& operator=(const String& scopy); // 대입연산자
	String operator+(const String& str2); // '+'연산자 오버라이딩
	String& operator +=(const String& str2); // '+='연산자 오버라이딩
	bool operator==(const String& str2); // '=='연산자 오버라이딩
/* '<< , >>'연산자 오버라이딩
1. 입/출력 함수
2. 전역함수
3. friend선언으로 클래스 멤버변수 접근 가능
*/
	friend ostream& operator<<(ostream& cout, const  String& str); // 출력
	friend istream& operator>>(istream& cin, String& str); // 입력
};
  1. account.h
  • "가상 클래스, 상속의 대상이 되는 기초 클래스"
#pragma once
#include<iostream>
using namespace std;

class Account;
typedef Account* ACCOUNT_PTR; // Account * 형을 ACCOUNT_PTR로 정의(Account의 포인터형)

// 고객등급별 상이한 특별이율
namespace TYPE
{
	enum
	{
		NORMAL = 1, HIGH
	};
}
// 거래 기능
enum
{
	MAKE = 1, DEPOSIT, WITHDRAW, SHOW, EXIT
};

// 고객명, 계좌번호 문자열 길이 fix
const int NAME_LEN = 30;
const int ID_LEN = 30;

// 가상 클래스, 기초 클래스
class Account
{
private:
	String acc_id;
	String acc_name;
	double acc_balance;

public:
	Account(String acc_id, String acc_name, double acc_seed);
	// 기타 재료함수
// 계좌번호 반환
	String Get_id();
// 잔금 반환
	double Get_balance();
// 함수에 접근하는 객체 형을 존중하는 virtual 선언 -> 가상함수.
// 입금
	virtual void Proccess_depos(double money);
// 출금
	void Proccess_withdraw(double money);
// Showinform() 함수 폐기
/* 배열 클래스 []연산자 오버로드 함수의 반환형으로 사용될
   1. Account
   2. Account *
   형을 받아들일 수 있는 매개변수형 지정, 출력(조회)에 사용할 "<<, >>"연산자 오버라이딩
   함수 선언
*/
	friend ostream& operator<<(ostream& cout, Account& ref);
	friend ostream& operator<<(ostream& cout, ACCOUNT_PTR& Aref); 
};
  1. accountarray.h
  • "Account 클래스 배열객체의 생성자, 연산자 오버라이딩함수를 멤버로 갖는 Accountarray 클래스가 존재하는 헤더파일"
#include "account.h"
#pragma once
using namespace std;

/*Accountarray*/
class Accountarray
{
private:
	ACCOUNT_PTR* arr; 
/* 앞서 정의한 Account의 포인터형 ACCOUNT_PTR의 재차 포인터형 "ACCOUNT_PTR *"형 으로 
   동적할당 주소를 받을 arr 변수를 정의한다.
*/ 
	int len; // 배열의 길이
/* **'배열'**이라 함은 고유주소 내 고유 값을 지닌 형태를 떠올리는 것이 일반적이다. 배열을 복사
   한다는 것은 무언가 잘못되었거나 어불성설일 가능성이 높다. 따라서 복사와 관련된 
   1. 복사생성자
   2. 대입연산자
   를 private 접근성으로 제한하여 클래스 **외부에서 호출하지 못하게(복사하지 못하게)** 한다.
*/
// 복사생성자, 대입연산자
	Accountarray(Accountarray& Acopy);
	Accountarray& operator=(Accountarray& Acopy);

public:
/* 디폴트 생성자 - Accountarray클래스 객체 생성(생성자 호출 시) 별도의 인자는 
   받지 않겠다는 뜻 -> 배열의 길이를 본인이 임의로 고정하는 것이 낫다는 판단에서..
*/
	Accountarray();
/*
  Account 멤버 내 함수들에 접근하려면 Account 클래스의 포인터형이 되어야 한다. 따라서
  반환형을 Account * 에 해당하는 ACCOUNT_PTR 또는 그의 참조형으로 선언한 것!
*/
// '[]'연산자 오버라이딩
	ACCOUNT_PTR& operator[](int idx); 
	ACCOUNT_PTR operator[](int idx) const; // 포인터형으로 반환 (Account 기준)
	int Getlen(); // 배열 길이 반환
  ~Accountarray(); // 소멸자 - 생성자 내 동적할당 소멸
};
  1. normal.h
  • "기본 Account 클래스에 입금 시 입금액에 **원금이율을 더하는* 특성을 지닌 Normal클래스를 갖는 헤더파일"
#include "account.h"
#include "string.h"
#pragma once

class Normal : public Account // public 범위로 상속
{
private:
	double acc_rate; // 일반 이율

public:
// 생성자
	Normal(String id, String name, double seed, double rate);
// 입금함수 오버로드 1
	void Proccess_depos(double money);
// 일반 이율 반환
	double Getrate();
};
  1. high.h
  • "Normal 클래스에 특별이율이 추가된 High클래스를 갖는 헤더파일"
#include "normal.h"
#include "string.h"
#pragma once

class High : public Normal
{
private:
	// 고객등급, 특별이율
	char acc_type;
	double acc_srate;

public:
// 생성자
	High(String id, String name, double seed, double rate, char type);
// 입금함수 오버로드 2
	void Proccess_depos(double money);
};
  1. accounthandler.h
  • "기능적 역할(계좌 생성, 입금, 출금, 조회)을 하는 Accounthandler클래스를 갖는 헤더파일"
#include "accountarray.h"
#pragma once

class Accounthandler
{
private:
	Accountarray acc; // 배열클래스 객체 생성
	int acc_count; // 고객 고유번호
public:
/* 생성자(배열클래스의 생성자 호출에서 이미동적할당이 이뤄지고 이에대한 소멸자도 정의
    되어 있으니 추가적인 소멸자 선언은 필요치 않다)
*/
	Accounthandler();
	// 기능함수(메뉴, 개설, 입금, 출금, 조회)
	void Menu();
	void Make();
	void Deposit();
	void Withdraw();
	void Show();
};

Sourcefiles - definition

파일 별 설명은 위 헤더파일의 설명과 동일!

  1. string.cpp
#include "string.h"
#include <iostream>
#include<cstring>
using namespace std;

// 생성자1 (default)
String::String()
{
    len = 0;
    str = 0; // default = NULL
}
// 생성자2
String::String(const char* Str)
{
// 동적할당
    len = strlen(Str) + 1;
    str = new char[len];
    strcpy(str, Str);
}
// 복사생성자
String::String(const String& scopy)
{
// 동적할당
    len = scopy.len + 1;
    str = new char[len];
    strcpy(str, scopy.str);
}
// 대입연산자
String& String::operator=(const String& scopy)
{
// 동적할당
    len = scopy.len + 1;
    str = new char[len];
    strcpy(str, scopy.str);
    return *this;
}
// 연산자 오버라이딩 함수
// '+'
String String::operator+(const String& str2)
{
    if (str == NULL)
    {
        exit(1);
    }
    int len2 = len + str2.len - 1; // \n을 위한 중복공간 한개 삭제(+1 +1 -1)
    char* tempstr = new char[len2]; // 임시공간(주소) 동적할당
    strcpy(tempstr, str); // str 복사
    strcat(tempstr, str2.str); // str2.str 이어붙임
    String temps(tempstr); // String 객체 생성(생성자 호출)
    return temps; // 생성된 객체 반환(임시 객체 !!)
}
// '+='
String& String::operator +=(const String& str2)
{
    if (str == NULL)
    {
        exit(1);
    }
    *this = *this + str2;
    return *this;
}
// '=='
bool String::operator==(const String& str2) // 문자열 일치 확인, boolean function
{
    if (str == NULL)
    {
        exit(1);
    }
    if (strcmp(str, str2.str) == 0)
        return true;
    else
        return false;
}
// '<<, >>' 입출력 함수
ostream& operator<<(ostream& cout, const  String& str1)
{
    cout << str1.str << endl;
    return cout;
}
istream& operator>>(istream& cin, String& str1)
{
    char str[100];
    cin >> str; // 문자열 입력
    str1 = String(str); 
// 대입 연산자를 호출하여 해당 문자열을 인자로 갖는 String 객체를 복사 
    return cin;
}
  1. account.cpp
#include "account.h"
#include "string.h"
#include<iostream>
using namespace std;

/*about Account class*/
// 생성자
Account::Account(String Acc_id, String Acc_name, double acc_seed)
    :acc_balance(acc_seed)
{
// String클래스 대입연산자 호출(동적할당 자동 진행)
    acc_id = Acc_id;
    acc_name = Acc_name;
}

// 기타 재료함수
// 계좌번호 반환
String Account::Get_id()
{
    return acc_id;
}
// 잔금 반환
double Account::Get_balance()
{
    return acc_balance;
}

/*
  계좌의 유형마다 입금방식이 다르기 때문에 입금함수 Proccess_depos는 오버로드될 것이며 
  배열 인자의 형에 따라 다른 오버로디드함수에 접근을 위해 virtual 선언
*/
// 입금함수
virtual void Account::Proccess_depos(double money)
{
    acc_balance += money;
}
// 출금함수
void Account::Proccess_withdraw(double money)
{
    acc_balance -= money;
}
// 조회함수 대체자, '<<'연산자 오버라이딩 함수. 반환형에 따라 인자형이 다르기에 두가지로 정의
ostream& operator<<(ostream& cout, Account& ref)
{
    cout << "계좌번호 : " << ref.acc_id ;
    cout << "성명 : " << ref.acc_name ;
    cout << "잔액 : " << ref.acc_balance << endl;;
    return cout;
}
ostream& operator<<(ostream& cout, ACCOUNT_PTR& pref)
{
    cout << *(pref);
    return cout;
}
  1. accountarray.cpp
#include "string.h"
#include "accountarray.h"
#include <cstdlib>
#include "account.h"

// 디폴트 생성자
Accountarray::Accountarray()
    :len(100) // 배열길이는 100으로 고정
{
    arr = new ACCOUNT_PTR[100]; // 길이 100의 ACCOUNT_PTR형 배열을 동적할당 생성
}

// '[]'연산자 오버라이딩 함수 - ACCOUNT_PTR & 반환형
ACCOUNT_PTR& Accountarray::operator[](int idx) // idx는 인자번호(고유번호)의미
{
    if (idx < 0 || idx >= len)
    {
        cout << "out of range" << endl;
        exit(1);
    }
    return arr[idx]; // 배열 인자 반환
}
// '[]'연산자 오버라이딩 함수 - ACCOUNT_PTR 반환형
ACCOUNT_PTR Accountarray::operator[](int idx) const
{
    if (idx < 0 || idx >= len)
    {
        cout << "out of range" << endl;
        exit(1);
    }
    return arr[idx];
}
// 소멸자
Accountarray::~Accountarray()
{
   delete []arr;
}
  1. normal.cpp
#include "account.h"
#include "normal.h"

/*about Normal class*/
// 생성자
Normal::Normal(String Acc_id, String Acc_name, double acc_seed, double rate)
    : acc_rate(rate), Account(Acc_id, Acc_name, acc_seed) // 이니셜라이저 이용
{
}

// 입금함수 오버로드1. 일반이율 고려
void Normal::Proccess_depos(double money)
{
// 총 입금액(추가액) = 입금액 + 원금*일반이율 
    Account::Proccess_depos(money + Account::Get_balance() * acc_rate);
}
// 일반이율 반환함수
double Normal::Getrate()
{
    return acc_rate;
}
  1. high.cpp
#include "high.h"
#include "account.h"

High::High(String id, String name, double seed, double rate, char type)
    : Normal(id, name, seed, rate)
{
    // 인자로 입력받은 등급별 상이한 특별 이율 초기화
    switch (type)
    {
    case 'A':
    {
        acc_srate = 0.07;
        break;
    }
    case 'B':
    {
        acc_srate = 0.04;
        break;
    }
    case 'C':
    {
        acc_srate = 0.02;
        break;
    }
    default:
    {
        cout << "유형을 재입력 하세요" << endl;
    }
    }
}

// 입금함수 오버로드2. 특별이율까지 고려한 모습
void High::Proccess_depos(double money)
{
// 총 입금액 = 입금액 + 원금 *(일반이율 + 특별이율)
    Account::Proccess_depos(money + Account::Get_balance() * (Getrate() + acc_srate));
}
  1. accounthandler.cpp
#include "accountarray.h"
#include "string.h"
#include "accounthandler.h"
#include <iostream>
#include "normal.h"
#include "high.h"
#include "accountarray.h"
using namespace std;
#include "account.h"

/*about Handler class*/
// 생성자
Accounthandler::Accounthandler()
    :acc_count(0) // 고객번호는 0부터 시작
{} // 배열클래스 객체 생성 시 동적할당이 이미 이루어져 별도의 정의가 필요하지 않음

// 기능 함수
// 메뉴
void Accounthandler::Menu()
{
    cout << "-------------------------------------------------" << endl;
    cout << "가능 업무" << endl;
    cout << "1. 계좌 생성 " << endl;
    cout << "2. 입금" << endl;
    cout << "3. 출금" << endl;
    cout << "4. 조회" << endl;
    cout << "5. 프로그램 종료" << endl;
}
// 생성
void Accounthandler::Make()
{
    String id;
    String name;
    int balance;
    int type;
// 고객 신상정보 입력
    cout << "계좌번호 : "; cin >> id;
    cout << "성명     : "; cin >> name;
    cout << "예치금   : "; cin >> balance;
    cout << "[계좌유형 결정]" << endl;
    cout << "(Normal=1/High=2) : "; cin >> type;
    double rate; // 일반 이율
    char acc_level; // 고객 등급
    // 계좌 유형에 따라 다른 형으로 동적할당이 진행됨
    switch (type)
    {
    case TYPE::NORMAL:
    {
        cout << "이율   : "; cin >> rate; // 일반이율 입력
        acc[acc_count++] = new Normal(id, name, balance, rate);
/* 
배열클래스의 '[]'연산자 오버로딩함수 호출. acc[acc_count++]는 ACCOUNT_PTR&형
이며 이는 Account *와 동치이다. Account는 Normal의 상위 클래스이기 때문에 Normal형으로
동적할당이 가능한 것
*/
       break;
    }
    case TYPE::HIGH:
    {
        cout << "이율   : "; cin >> rate; // 일반이율
        cout << "고객등급 : "; cin >> acc_level; // 고객 등급
        acc[acc_count++] = new High(id, name, balance, rate, acc_level);
// 마찬가지 Account클래스는 High의 상위 클래스, 동적할당 가능
    }
   }
}

// 입금함수
void Accounthandler::Deposit()
{
    String id;
    int money;
// 계좌번호 입력
    cout << "계좌번호 입력 : "; cin >> id;
    for (int i = 0; i < acc_count; i++)
    {
        if (acc[i]->Get_id() == id) // 계좌번호 일치 확인
        {
            cout << "금액(만원) : "; cin >> money; // 일치 시 입금액 입력
  // 입금함수는 가상함수, 오버로드 함수이다. 
            acc[i]->Proccess_depos(money);
            cout << "정상 입금 되었습니다." << endl;
            break;
        }
        else if (i == acc_count - 1) // 불일치 시
            cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
    }
}
// 출금함수
void Accounthandler::Withdraw()
{
    String id;
    int money;
// 계좌번호 입력
    cout << "계좌번호 입력 : "; cin >> id;
    for (int i = 0; i < acc_count; i++)
    {
        if (acc[i]->Get_id() == id) // 계좌번호 일치 확인
        {
            cout << "금액(만원) : "; cin >> money;
// 출금함수는 오버로드 함수도 가상함수도 아니다. 오직 한개만 존재(in Account class)
            acc[i]->Proccess_withdraw(money);
            cout << "정상 출금 되었습니다." << endl;
        }
        else if (i == acc_count - 1) // 불일치 시
            cout << "계좌번호가 정확히 입력되었는지 확인하세요" << endl;
    }
}
// 조회함수
void Accounthandler::Show()
{
    cout << "------------------" << endl;;
    for (int i = 0; i < acc_count; i++)
    {
        cout << acc[i]; 
// Account함수에서 **전역함수로** 정의한 '<<'연산자 오버라이딩 함수 호출
    }
}
  1. main,cpp
#include "account.h"
#include "accountarray.h"
#include "accounthandler.h"
#include "normal.h"
#include "high.h"
#include "string.h"
#include <iostream>
#include <cstring>
int main()
{
	Accounthandler AH; // controller 객체 생성, 기능 함수 접근
	int choice;
	while (1)
	{
		AH.Menu();
		cout << "거래를 선택하세요 : "; cin >> choice;
		switch (choice)
		{
		case MAKE:
		{
			AH.Make(); // 기능함수 - 생성
			break;
		}
		case DEPOSIT:
		{
			AH.Deposit(); // 기능함수 - 입금
			break;
		}
		case WITHDRAW:
		{
			AH.Withdraw(); // 기능함수 - 출금
			break;
		}
		case SHOW:
		{
			AH.Show(); // 기능함수 - 조회
			break;
		}
		case EXIT: // 종료
		{
			cout << "거래를 종료합니다." << endl;
			return 0;
		}
		default: // 그 외 옵션 입력 시
		{
			cout << "다른 옵션을 선택하세요" << endl;
		}
		}
		char further[5];
		cout << "거래를 계속 하시겠습니까?(yes / no) : "; cin >> further;
		if (strcmp(further, "no") == 0)
		{
			return 0;
		}
	}
	return 0;
}

3. Result

(i think.. regard to operation issues of the main body, no further explanation is needed. if you want, refer to the account project ver1 ~ ver4 in series "Miniproject")

and Obviously, all the other options were compiled with no errors.


4. 결론

미리 원하는 클래스 객체의 배열 에 대한 생성 ~ 연산자를 관장하는 배열클래스를 만들어 활용할 수 있다. 이는 컨트롤러 클래스의 간소화로 이어진다.

profile
미생 개발자

0개의 댓글