Updated as follows
#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); // 입력
};
#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);
};
#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(); // 소멸자 - 생성자 내 동적할당 소멸
};
#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();
};
#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);
};
#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();
};
파일 별 설명은 위 헤더파일의 설명과 동일!
#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;
}
#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;
}
#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;
}
#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;
}
#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));
}
#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함수에서 **전역함수로** 정의한 '<<'연산자 오버라이딩 함수 호출
}
}
#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;
}
(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.
미리 원하는 클래스 객체의 배열 에 대한 생성 ~ 연산자를 관장하는 배열클래스를 만들어 활용할 수 있다. 이는 컨트롤러 클래스의 간소화로 이어진다.