상속의 목적은 명확해야 하고 그렇지 않다면 안하는 편이 좋다.
상속이 필요한 대표적이며 중요한 이유, 이점을 정리해본다.
공통적인 기능을 묶어 추가 삭제 등 변경사항이 생겨도 자식 클래스에 일일히 적용하지 않아도 된다 -> 확장성이 좋다
다른 곳에도 구현해 둔 클래스를 붙였다 뗐다 할 수 있다 -> 재사용이 가능
● 장점 : 유지보수가 쉬워지고, 확장성이 좋아지며, 모듈화를 통해 재사용이 가능하며, 코드가 간결해져 개발시간을 단축시킬 수 있다.
과거 진행한 OOP 단계별 프로젝트
[윤성우 열혈 c++] OOP 단계별 프로젝트 01단계
[윤성우 열혈 c++] OOP 단계별 프로젝트 02단계
[윤성우 열혈 c++] OOP 단계별 프로젝트 03단계
[윤성우 열혈 c++] OOP 단계별 프로젝트 04단계
[윤성우 열혈 c++] OOP 단계별 프로젝트 05단계
프로그램 설명
기존 Account 클래스에는 이자와 관련한 부분이 없으니 6단계에서는 Account 클래스를 상속하는 2개의 클래스를 추가 정의한다.
1) NormalAccount : 보통예금계좌 (최소한의 이자를 지급하는 자유입출금계좌)
2) HighCreditAccount : 신용신뢰계좌 (신용도가 높은 일부 고객만 개설되는 높은 이율 계좌)
NormalAccount 클래스는 객체의 생성 과정에서(생성자를 통해) 이율정보를 등록할 수 있게 정의한다.
HighCreditAccount 클래스에는 다음 특성을 부여해 정의하자.
1) NormalAccount 클래스처럼 객체 생성과정에서 기본이율을 등록할 수 있다
2) 고객의 신용등급을 A, B, C로 나누고 계좌개설 시 신용등급 정보를 등록한다.
3) A, B, C 등급별로 각각 기본이율에 7%, 4%, 2%의 이율을 추가 제공한다.
편의상 이자는 입금 시 이자가 원금에 더해지는 것으로 계산한다.
모든 계좌에는 다음 조건을 적용한다.
1) 계좌개설 과정에서 초기 입금되는 금액에 대해서는 이자를 계산하지 않는다.
2) 계좌개설 후 별도의 입금과정을 거칠 때에만 이자가 발생하는 것으로 간주한다.
3) 이자의 계산과정에서 발생하는 소수점 이하의 금액은 무시한다.
컨트롤 클래스인 AccountHandler 클래스에는 큰 변화가 없어야 한다.
(계좌의 종류가 늘어난 만큼 메뉴의 선택과 데이터의 입력과정에서의 불가피한 변경은 허용)
실행의 예
계좌의 개설과정 1
-----Menu-----
1. 계좌개설
2. 입금
3. 출금
4. 계좌번호 전체 출력
5. 프로그램 종료
선택: 1
[계좌종류선택]
1. 보통예금계좌 2. 신용신뢰계좌
선택 : 1
[보통예금계좌 개설]
계좌ID: 123
이름: 이종석
입금액: 0
이자율: 3
계좌의 개설과정 2
-----Menu-----
1. 계좌개설
2. 입금
3. 출금
4. 계좌번호 전체 출력
5. 프로그램 종료
선택: 1
[계좌종류선택]
1. 보통예금계좌 2. 신용신뢰계좌
선택 : 2
[신용신뢰계좌 개설]
계좌ID: 7272
이름: 이수혁
입금액: 10000
이자율: 9
신용등급(1toA, 2toB, 3toC): 2
구현코드는 나름대로 나눠서 정리해 봤다.
BankingSystemMain.cpp
// BankingSystemVer06.cpp - 은행 계좌 관리 프로그램 6
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include "Account.h"
#include "AccountHandler.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"
using namespace std;
//1. 계좌개설
//2. 입금
//3. 출금
//4. 계좌번호 전체 출력
//5. 프로그램 종료
enum { MAKE = 1, DEPOSIT, WITHDRAW, INQUIRE, EXIT };
/********** 메인 클래스 AccountHandler **********/
int main()
{
AccountHandler hdr;
int choice;
while (1)
{
hdr.ShowMenu(); //메뉴선택모드
cout << "선택(1~5까지의 숫자만 입력) : ";
cin >> choice;
cout << endl;
switch (choice)
{
case MAKE:
hdr.MakeAccount();
break;
case DEPOSIT:
hdr.DepositMoney();
break;
case WITHDRAW:
hdr.WithdrawMoney();
break;
case INQUIRE:
hdr.ShowAllAccInfo();
break;
case EXIT:
return 0;
default:
cout << "잘못된 선택" << endl;
}
}
return 0;
}
Account.h, Account.cpp
#pragma once
class Account {
private:
int accID; //계좌 ID
int balance; // 잔액
char* cusName; //고객이름
public:
Account(int _accID, int _balance, char* _name); //생성자
Account(const Account& ref); //복사생성자
int GetAccID() const; // 계좌 ID 반환
virtual void Deposit(int money); // 입금 //virtual 추가
int WithDraw(int money); // 출금
void ShowAccInfo() const; // 개인계좌조회
~Account(); // 소멸자
};
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Account.h"
using namespace std;
// Account 생성자
Account::Account(int _accID, int _balance, char* _name) // 계좌개설 - ID, 고객이름, 돈
: accID(_accID), balance(_balance)
{
cusName = new char[strlen(_name) + 1]; //고객이름 객체 포인터로 동적할당
strcpy(cusName, _name);
}
// 실제 호출되지는 않는 Account복사생성자
// 깊은 복사를 원칙으로 정의
Account::Account(const Account& ref)
: accID(ref.accID), balance(ref.balance)
{
cusName = new char[strlen(ref.cusName) + 1]; //고객이름 객체 포인터로 동적할당
strcpy(cusName, ref.cusName);
}
// Account 소멸자
Account::~Account() // 소멸자
{
delete[] cusName;
}
// 계좌 ID 반환
int Account::GetAccID() const // 내부 출력문이나 값의 변동이 없는 경우 const
{
return accID;
}
// 개인 계좌조회
void Account::ShowAccInfo() const
{
// 내부 출력문이나 값의 변동이 없는 경우 const
cout << "계좌ID: " << accID << endl;
cout << "이름: " << cusName << endl;
cout << "잔액: " << balance << endl << endl;
}
// 입출금
void Account::Deposit(int money)
{
balance += money;
}
int Account::WithDraw(int money)
{
if (balance < money) //잔액<출금액
{
return 0;
}
balance -= money;
return money;
}
AccountHandler.h, AccountHandler.cpp
#pragma once
/********** 컨트롤 클래스 AccountHandler **********/
class AccountHandler {
private:
// 전역 변수였던 것들
Account* accArr[100]; //Account 저장을 위한 배열
int accNum; //저장된 Account 수
public:
AccountHandler(); //생성자
// 전역함수였던 것들
void ShowMenu(void) const; //메뉴출력
void MakeAccount(void); //계좌개설
void DepositMoney(void); //입금
void WithdrawMoney(void); //출금
void ShowAllAccInfo(void) const; //잔액조회
void MakeNormalAccount(); // 보통예금계좌 개설
void MakeHighCreditAccount(); // 신용신뢰계좌 개설
~AccountHandler(); //소멸자
};
#include <iostream>
#include "Account.h"
#include "AccountHandler.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"
using namespace std;
const int NAME_LEN = 20; //이름의길이
//메뉴출력
void AccountHandler::ShowMenu(void) const {
cout << "-----Menu-----" << endl;
cout << "1. 계좌개설" << endl;
cout << "2. 입금" << endl;
cout << "3. 출금" << endl;
cout << "4. 계좌번호 전체 출력" << endl;
cout << "5. 프로그램 종료" << endl;
}
// AccountHandler 생성자
AccountHandler::AccountHandler()
: accNum(0)
{}
// AccountHandler 소멸자
AccountHandler::~AccountHandler()
{
for (int i = 0; i < accNum; i++)
{
delete accArr[i];
}
}
// 계좌종류
enum AccountType { NORMAL = 1, HIGHCREDIT };
// 신용등급
enum CreditRating { A = 7, B = 4, C = 2 };
//계좌개설
void AccountHandler::MakeAccount(void)
{
/* int id;
char name[NAME_LEN];
int balance;*/
int accountType;
/* cout << "[계좌개설]" << endl;
cout << "계좌ID:(숫자로 입력) "; cin >> id;
cout << "이름: "; cin >> name;
cout << "입금액: "; cin >> balance;
cout << endl;
accArr[accNum++] = new Account(id, balance, name);*/
cout << "[계좌종류선택]" << endl;
cout << "1. 보통예금계좌 2. 신용신뢰계좌" << endl;
cout << "선택(숫자입력) : "; cin >> accountType;
if (accountType == NORMAL) //보통예금계좌
{
MakeNormalAccount();
}
else // 신용신뢰계좌
{
MakeHighCreditAccount();
}
}
// 보통예금계좌 개설
void AccountHandler::MakeNormalAccount()
{
int id;
char name[NAME_LEN];
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::MakeHighCreditAccount()
{
int id;
char name[NAME_LEN];
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이며 1, 2, 3 중 입력): "; cin >> creditLevel;
cout << endl;
// 신용등급 처리
switch (creditLevel)
{
case 1:
// 1을 입력했을 때
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, A); //7%
break;
case 2:
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, B); //4%
break;
case 3:
accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, C); //2%
break;
}
}
//입금
void AccountHandler::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 AccountHandler::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 AccountHandler::ShowAllAccInfo(void) const
{
for (int i = 0; i < accNum; i++)
{
accArr[i]->ShowAccInfo();
}
}
NormalAccount.h, NormalAccount.cpp
#pragma once
/**
* 객체를 생성할 때 계좌 기본이율을 등록할 수 있다
* 계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
* 이자계산액의 소수점 이하 금액은 무시한다. (버림)
*/
class NormalAccount: public Account //Account 상속
{
public:
NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate);
~NormalAccount();
private:
int basicInterestRate; // 기본이율 (%단위)
public:
//추가된 입금 + 이자율 계산식......뒤집어쓰니까 virtual
virtual void Deposit(int money);
};
#include <iostream>
#include "Account.h"
#include "NormalAccount.h"
NormalAccount::NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate)
: Account(_accID, _balance, _name), basicInterestRate(_basicInterestRate)
{ }
NormalAccount::~NormalAccount()
{ }
void NormalAccount::Deposit(int money)
{
Account::Deposit(money); //원금추가
Account::Deposit(money*(basicInterestRate/100.0)); //이자추가
}
HighCreditAccounth, HighCreditAccount.cpp
#pragma once
/**
* 객체를 생성할 때 계좌 기본이율을 등록할 수 있다
* 계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
* 이자계산액의 소수점 이하 금액은 무시한다. (버림)
* 신용등급 정보 A(7%), B(4%), C(2%) 셋 중 하나를 계좌개설 시 등록한다.
* 등급별 기본이율에 각각의 이율을 추가 제공한다.
*/
class HighCreditAccount : public NormalAccount
{
public:
HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel);
~HighCreditAccount();
private:
int creditLevel; //신용등급
public:
virtual void Deposit(int money);
};
#include <iostream>
#include "Account.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"
HighCreditAccount::HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel)
: NormalAccount(_id, _balance, _name, _interRate), creditLevel(_creditLevel)
{ }
HighCreditAccount::~HighCreditAccount()
{ }
void HighCreditAccount::Deposit(int money)
{
NormalAccount::Deposit(money); //원금과 이자추가
Account::Deposit(money*(creditLevel/100.0)); // 특별이자 추가
}
'C, C++ > 열혈 C++ 프로그래밍' 카테고리의 다른 글
[윤성우 열혈 c++] OOP 단계별 프로젝트 07단계 (0) | 2021.11.22 |
---|---|
[C++] 복사생성자 호출 시점 3가지 (중요) (0) | 2021.11.15 |
[윤성우 열혈 C++ 프로그래밍] 10. 연산자 오버로딩 1 (책) (0) | 2021.11.05 |
[윤성우 열혈 c++] OOP 단계별 프로젝트 05단계 (0) | 2021.11.04 |
[윤성우 열혈 c++] OOP 단계별 프로젝트 04단계 (0) | 2021.11.04 |