在基類Account中將賬戶的公共操作皆聲明爲虛函數,因此可以通過基類的指針來執行各種操作,因而各種類型的賬戶對象都可以通過一個指針的數組來訪問。
//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,int month,int day);//用年月日構造日期
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;
}
};
#endif
//date.cpp
#include"date.h"
#include<cstdlib>
#include<iostream>
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++;
}
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
//account.h
#ifndef _ACCOUNT_H_
#define _ACCOUNT_H_
#include"date.h"
#include"accumulator.h"
#include<string>
#include<iostream>
using namespace std;
class Account //賬戶類
{
private:
string id;//賬號
double balance;//餘額
static double total;//所有賬戶的總金額
protected:
//供派生類調用的構造函數,id爲賬戶
Account(const Date &date,const string &id);
//記錄一筆賬,日期,金額,說明
void record(const Date &date,double amount,const string &desc);
//報告錯誤信息
void error(const string &msg)const;
public:
const 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 string &desc)=0;
//取出現金
virtual void withdraw(const Date &date,double amount,const string &desc)=0;
//結算(計算利息、年費),每月結算一次,date爲結算日期
virtual void settle (const Date &date)=0;
virtual void show()const;
};
class SavingsAccount:public Account//儲蓄賬戶類
{
private:
Accumulator acc;//輔助計算利息的累加器
double rate;//存款年利率
public:
SavingsAccount(const Date&date,const string &id,double rate);//構造函數
double getRate()const{return rate;}
void deposit(const Date &date,double amount,const string &desc);//存入現金
void withdraw(const Date &date,double dmount,const string &desc);//取出現金
void settle(const Date &date);//結算利息,每年1月1日調用一次該函數
};
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 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;
}
void deposit(const Date &date,double amount,const string &desc);//存入現金
void withdraw(const Date &date,double dmount,const string &desc);//取出現金
void settle(const Date &date);//結算利息和年費,每月1日調用一次該函數
void show()const;
};
#endif
//account.cpp
#include"account.h"
#include<cmath>
#include<iostream>
using namespace std;
double Account::total=0;
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;
date.show();
cout<<"\t#"<<id<<"\t"<<amount<<"\t"<<balance<<"\t"<<desc<<endl;
}
void Account::show()const
{
cout<<id<<"\tBalance: "<<balance;
}
void Account::error(const string &msg)const
{
cout<<"Error(#"<<id<<"):"<<msg<<endl;
}
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(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 money");
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<iostream>
using namespace std;
int main()
{
Date date(2008,11,1);//起始日期
//建立幾個賬戶
SavingsAccount sa1(date,"s3755217",0.015);
SavingsAccount sa2(date,"02342342",0.015);
CreditAccount ca(date,"C5392394",10000,0.0005,50);
Account * accounts[]={&sa1,&sa2,&ca};
const int n=sizeof(accounts)/sizeof(Account*);//賬戶總數
cout<<"(d)deposit(w)withdraw(s)show(c)change day(n)next month(e)exit"<<endl;
char cmd;
do{
date.show();
cout<<"\tTotal: "<<Account::getTotal()<<"\tcommand>";
int index,day;
double amount;
string desc;
cin>>cmd;
switch(cmd)
{
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(int i=0;i<n;++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(int i=0;i<n;++i)
accounts[i]->settle(date);
break;
}
}while (cmd!='e');
return 0;
}