用一个还比较成规模的实例来强化各项语法的熟练度
一、初步需求描述
成员数据
账户名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;
else
this->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_H
class 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
用本地文件存储历史记录
六、异常
异常状况捕捉