用一个还比较成规模的实例来强化各项语法的熟练度
一、初步需求描述
成员数据
账户名id、余额balance、利率rate、上一次余额变动日期lastDate、日均余额的累计值accumulation
成员函数
显示账户信息show、存款deposit、取款withdraw、结算settle、修改内部数据的函数record、计算截止至指定日期的账户余额按日累计值accumulate
为方便起见,传入的date是一个相对日期,以天为单位。这样相见就知道利率的天数
实现难点
利率计算
年利 != 余额 × 年利率
应该按照日结来计算,而非年结:年利 = 日均余额 × 年利率。比如(年利1.5%):
第5天存入5000,第45天存入5500,第90天结算:
利息 = ((45-5)×5000+(90-45)*(5000+5500))/365 × 1.5% = 27.64
四舍五入与有效精度
向下取整(高斯函数)floor()
向上取整ceil()
对一个数x做四舍五入:floor(x+0.5) //强制转int会直接丢失小数
对一个数x保留小数点后两位:floor(x*100+0.5)/100
更进一步
- 查看当前所有账户的总金额
- 使用静态数据和静态函数
- 修改日期表示方式
- 创建一个日期类型
代码实现
SavingsAccount.h
#ifndef SAVINGS_ACCOUNT_H#define SAVINGS_ACCOUNT_H#include <string>#include "Date.h"using namespace std;class SavingsAccount{private:static double total;string id;double balance;double rate;double accumulation;Date date;void record(Date date, double amount);public:SavingsAccount() = default;SavingsAccount(string id, double balance,Date date , double rate = 0.015);~SavingsAccount();void show() const;string getId() const;double getBlance() const;double getRate() const;void deposit(Date date , double amount);void withdraw(Date date, double amount);void settle(Date date);void accumulate(Date date);static double getTotal();};#endif
Savings_account.cpp
#include "SavingsAccount.h"#include "Date.h"#include <string>#include <iostream>#include <cmath>using namespace std;using SA = SavingsAccount;double SA::total = 0.0;void SA::record(Date date, double amount){accumulate(date);this->date = date;balance += amount;total+=amount;}SA::SavingsAccount(string id, double balance,Date date, double rate):id(id),balance(balance),rate(rate),date(date),accumulation(0){total += balance;}SA::~SavingsAccount(){}string SA::getId() const{ return id;}double SA::getBlance() const{ return balance;}double SA::getRate() const{return rate;}double SA::getTotal(){ return total;}void SA::show() const{cout.width(10);cout<<id;cout.width(10);cout<<accumulation;cout.width(10);cout<<balance<<"("<<rate<<")"<<endl;}void SA::deposit(Date date , double amount){this->record(date,amount);show();}void SA::withdraw(Date date, double amount){if(amount>balance)cout<<"取款失败,透支了"<<endl;elsethis->record(date,-amount);show();}void SA::settle(Date date){accumulate(date);this->date = date;double change = floor(accumulation*rate/365*100 +0.5)/100;total+= change;balance+=change;accumulation = 0;show();}void SA::accumulate(Date date){accumulation += floor((date - this->date)*balance*100 + 0.5)/100;}
main_SA.cpp
#include <iostream>#include <string>#include "SavingsAccount.h"using namespace std;using SA = SavingsAccount;int main(){SA myAcc[] = {SA("PA001",0.0,Date(2020,1,10)),SA("PA399",0.0,Date(2020,4,30))};myAcc[1].deposit(Date(2020,1,15),5000);myAcc[1].deposit(Date(2020,2,24),5500);myAcc[1].settle(Date(2020,4,9));myAcc[0].deposit(Date(2020,5,5),2000);myAcc[0].settle(Date(2020,12,20));cout<<SA::getTotal()<<endl;cout<<Date(2020,4,9) - Date(2020,3,10)<<endl;return 0;}
Date.h
#ifndef DATE_H#define DATE_Hclass Date{private:int year;int month;int day;bool falg_run;public:Date(int year, int month, int day);~Date() = default;int operator-(const Date &d);bool isRun(int y);};#endif
Date.cpp
#include "Date.h"int Month_nor[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int Month_run[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };Date::Date(int year, int month , int day):year(year),month(month),day(day){falg_run = isRun(year);}int Date::operator-(const Date & d){int result = 0;result += day;result -= d.day;for(int i = 1 ; i< month;++i)falg_run? result+=Month_run[i]:result+=Month_nor[i];for(int i = 1 ; i<d.month;++i)d.falg_run?result-=Month_run[i]:result-=Month_nor[i];for(int i = d.year ; i< year; ++i){isRun(i)?result+=366:result+=365;}return result;}bool Date::isRun(int year){if((year%400) || !(year%100)&&(year%4) )return true;return false;}
二、增加信用账户
这里使用类的继承与派生相关知识,用来新增一个信用卡账户。

需求说明
信用卡账户特点
- 允许透支和信用额度
- 利息:存钱没有利息,透支超过免息期会有利息(暂不考虑)。
- 结算一月一次,假定每月1日
- 每年交一次年费,假定1月1日
输出格式
账户创建信息
流水:日期 账户 交易金额 余额 备注
最后输出:每个账户的余额 + 信用卡的额度
所有账户的总余额 (扣除信用卡欠款)
程序实现
代码不多,但是复杂的文件系统让人头晕。这里面最关键的就是数据成员被封装之后,不知道某个数据存到哪里去了。子类之间跟共同基类如何协调。我觉得需要更加清晰的图示。

所以接下来的代码可能会转移到vs中编写。
三、虚函数统一接口
增加交互要求:


通过一个基类指针和可以实现不同账户的不同动作
通过一个指针数组就可以保存不同的账户
代码完成不再赘述,最后工程文件会上传到仓库
四、容器模板
用vector容器存储对象
用map存储历史记录
五、IO
用本地文件存储历史记录
六、异常
异常状况捕捉
