【C++脳図シリーズ09】汎用プログラム設計とSTL
86010 ワード
脳図
コード#コード#
コード#コード#
//date.h
#ifndef __DATE_H__
#define __DATE_H__
class Date { //
private:
int year; //
int month; //
int day; //
int totalDays; // 1 1
public:
Date(int year = 1, int month = 1, int day = 1); // 、 、
static Date read();
int getYear() const { return year; }
int getMonth() const { return month; }
int getDay() const { return day; }
int getMaxDay() const; //
bool isLeapYear() const { //
return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}
void show() const; //
//
int operator - (const Date& date) const {
return totalDays - date.totalDays;
}
//
bool operator < (const Date& date) const {
return totalDays < date.totalDays;
}
};
#endif //__DATE_H__
//date.cpp
#include "date.h"
#include
#include
using namespace std;
namespace { //namespace
// 1 , getMaxDay ,
const int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
}
Date::Date(int year, int month, int day) : year(year), month(month), day(day) {
if (day <= 0 || day > getMaxDay()) {
cout << "Invalid date: ";
show();
cout << endl;
exit(1);
}
int years = year - 1;
totalDays = years * 365 + years / 4 - years / 100 + years / 400
+ DAYS_BEFORE_MONTH[month - 1] + day;
if (isLeapYear() && month > 2) totalDays++;
}
Date Date::read() {
int year, month, day;
char c1, c2;
cin >> year >> c1 >> month >> c2 >> day;
return Date(year, month, day);
}
int Date::getMaxDay() const {
if (isLeapYear() && month == 2)
return 29;
else
return DAYS_BEFORE_MONTH[month]- DAYS_BEFORE_MONTH[month - 1];
}
void Date::show() const {
cout << getYear() << "-" << getMonth() << "-" << getDay();
}
//accumulator.h
#ifndef __ACCUMULATOR_H__
#define __ACCUMULATOR_H__
#include "date.h"
class Accumulator { //
private:
Date lastDate; //
double value; //
double sum; //
public:
// ,date ,value
Accumulator(const Date &date, double value)
: lastDate(date), value(value), sum(0) { }
// date
double getSum(const Date &date) const {
return sum + value * (date - lastDate);
}
// date value
void change(const Date &date, double value) {
sum = getSum(date);
lastDate = date;
this->value = value;
}
// , date, value,
void reset(const Date &date, double value) {
lastDate = date;
this->value = value;
sum = 0;
}
};
#endif //__ACCUMULATOR_H__
//account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include "date.h"
#include "accumulator.h"
#include
#include
class Account; //
class AccountRecord { //
private:
Date date; //
const Account *account; //
double amount; //
double balance; //
std::string desc; //
public:
//
AccountRecord(const Date &date, const Account *account, double amount, double balance, const std::string& desc);
void show() const; //
};
//
typedef std::multimap<Date, AccountRecord> RecordMap;
class Account { //
private:
std::string id; //
double balance; //
static double total; //
static RecordMap recordMap; //
protected:
// ,id
Account(const Date &date, const std::string &id);
// ,date ,amount ,desc
void record(const Date &date, double amount, const std::string &desc);
//
void error(const std::string &msg) const;
public:
const std::string &getId() const { return id; }
double getBalance() const { return balance; }
static double getTotal() { return total; }
// ,date ,amount ,desc
virtual void deposit(const Date &date, double amount, const std::string &desc) = 0;
// ,date ,amount ,desc
virtual void withdraw(const Date &date, double amount, const std::string &desc) = 0;
// ( 、 ), ,date
virtual void settle(const Date &date) = 0;
//
virtual void show() const;
//
static void query(const Date& begin, const Date& end);
};
class SavingsAccount : public Account { //
private:
Accumulator acc; //
double rate; //
public:
//
SavingsAccount(const Date &date, const std::string &id, double rate);
double getRate() const { return rate; }
virtual void deposit(const Date &date, double amount, const std::string &desc);
virtual void withdraw(const Date &date, double amount, const std::string &desc);
virtual void settle(const Date &date);
};
class CreditAccount : public Account { //
private:
Accumulator acc; //
double credit; //
double rate; //
double fee; //
double getDebt() const { //
double balance = getBalance();
return (balance < 0 ? balance : 0);
}
public:
//
CreditAccount(const Date &date, const std::string &id, double credit, double rate, double fee);
double getCredit() const { return credit; }
double getRate() const { return rate; }
double getFee() const { return fee; }
double getAvailableCredit() const { //
if (getBalance() < 0)
return credit + getBalance();
else
return credit;
}
virtual void deposit(const Date &date, double amount, const std::string &desc);
virtual void withdraw(const Date &date, double amount, const std::string &desc);
virtual void settle(const Date &date);
virtual void show() const;
};
#endif //__ACCOUNT_H__
//account.cpp
#include "account.h"
#include
#include
#include
using namespace std;
using namespace std::rel_ops;
//AccountRecord
AccountRecord::AccountRecord(const Date &date, const Account *account, double amount, double balance, const std::string& desc)
: date(date), account(account), amount(amount), balance(balance), desc(desc) { }
void AccountRecord::show() const {
date.show();
cout << "\t#" << account->getId() << "\t" << amount << "\t" << balance << "\t" << desc << endl;
}
//Account
double Account::total = 0;
RecordMap Account::recordMap;
Account::Account(const Date &date, const string &id)
: id(id), balance(0) {
date.show();
cout << "\t#" << id << " created" << endl;
}
void Account::record(const Date &date, double amount, const string &desc) {
amount = floor(amount * 100 + 0.5) / 100; //
balance += amount;
total += amount;
AccountRecord record(date, this, amount, balance, desc);
recordMap.insert(make_pair(date, record));
record.show();
}
void Account::show() const {
cout << id << "\tBalance: " << balance;
}
void Account::error(const string &msg) const {
cout << "Error(#" << id << "): " << msg << endl;
}
void Account::query(const Date& begin, const Date& end) {
if (begin <= end) {
RecordMap::iterator iter1 = recordMap.lower_bound(begin);
RecordMap::iterator iter2 = recordMap.upper_bound(end);
for (RecordMap::iterator iter = iter1; iter != iter2; ++iter)
iter->second.show();
}
}
//SavingsAccount
SavingsAccount::SavingsAccount(const Date &date, const string &id, double rate)
: Account(date, id), rate(rate), acc(date, 0) { }
void SavingsAccount::deposit(const Date &date, double amount, const string &desc) {
record(date, amount, desc);
acc.change(date, getBalance());
}
void SavingsAccount::withdraw(const Date &date, double amount, const string &desc) {
if (amount > getBalance()) {
error("not enough money");
} else {
record(date, -amount, desc);
acc.change(date, getBalance());
}
}
void SavingsAccount::settle(const Date &date) {
if (date.getMonth() == 1) { //
double interest = acc.getSum(date) * rate
/ (date - Date(date.getYear() - 1, 1, 1));
if (interest != 0)
record(date, interest, " interest");
acc.reset(date, getBalance());
}
}
//CreditAccount
CreditAccount::CreditAccount(const Date& date, const string& id, double credit, double rate, double fee)
: Account(date, id), credit(credit), rate(rate), fee(fee), acc(date, 0) { }
void CreditAccount::deposit(const Date &date, double amount, const string &desc) {
record(date, amount, desc);
acc.change(date, getDebt());
}
void CreditAccount::withdraw(const Date &date, double amount, const string &desc) {
if (amount - getBalance() > credit) {
error("not enough credit");
} else {
record(date, -amount, desc);
acc.change(date, getDebt());
}
}
void CreditAccount::settle(const Date &date) {
double interest = acc.getSum(date) * rate;
if (interest != 0)
record(date, interest, " interest");
if (date.getMonth() == 1)
record(date, -fee, " annual fee");
acc.reset(date, getDebt());
}
void CreditAccount::show() const {
Account::show();
cout << "\tAvailable credit:" << getAvailableCredit();
}
//main.cpp
#include "account.h"
#include
#include
#include
using namespace std;
struct deleter {
template <class T> void operator () (T* p) { delete p; }
};
int main() {
Date date(2008, 11, 1); //
vector<Account *> accounts; // , 0
cout << "(a)add account (d)deposit (w)withdraw (s)show (c)change day (n)next month (q)query (e)exit" << endl;
char cmd;
do {
//
date.show();
cout << "\tTotal: " << Account::getTotal() << "\tcommand> ";
char type;
int index, day;
double amount, credit, rate, fee;
string id, desc;
Account* account;
Date date1, date2;
cin >> cmd;
switch (cmd) {
case 'a': //
cin >> type >> id;
if (type == 's') {
cin >> rate;
account = new SavingsAccount(date, id, rate);
} else {
cin >> credit >> rate >> fee;
account = new CreditAccount(date, id, credit, rate, fee);
}
accounts.push_back(account);
break;
case 'd': //
cin >> index >> amount;
getline(cin, desc);
accounts[index]->deposit(date, amount, desc);
break;
case 'w': //
cin >> index >> amount;
getline(cin, desc);
accounts[index]->withdraw(date, amount, desc);
break;
case 's': //
for (size_t i = 0; i < accounts.size(); i++) {
cout << "[" << i << "] ";
accounts[i]->show();
cout << endl;
}
break;
case 'c': //
cin >> day;
if (day < date.getDay())
cout << "You cannot specify a previous day";
else if (day > date.getMaxDay())
cout << "Invalid day";
else
date = Date(date.getYear(), date.getMonth(), day);
break;
case 'n': //
if (date.getMonth() == 12)
date = Date(date.getYear() + 1, 1, 1);
else
date = Date(date.getYear(), date.getMonth() + 1, 1);
for (vector<Account*>::iterator iter = accounts.begin(); iter != accounts.end(); ++iter)
(*iter)->settle(date);
break;
case 'q': //
date1 = Date::read();
date2 = Date::read();
Account::query(date1, date2);
break;
}
} while (cmd != 'e');
for_each(accounts.begin(), accounts.end(), deleter());
return 0;
}