小項目之個人銀行賬戶管理程序(5)

在基類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;
}


發佈了57 篇原創文章 · 獲贊 32 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章