用一个还比较成规模的实例来强化各项语法的熟练度

一、初步需求描述

CPP课程综合实例 - 图1

成员数据

账户名id、余额balance、利率rate、上一次余额变动日期lastDate、日均余额的累计值accumulation

成员函数

显示账户信息show、存款deposit、取款withdraw、结算settle、修改内部数据的函数record、计算截止至指定日期的账户余额按日累计值accumulate

为方便起见,传入的date是一个相对日期,以天为单位。这样相见就知道利率的天数

实现难点

利率计算

年利 != 余额 × 年利率

应该按照日结来计算,而非年结:年利 = 日均余额 × 年利率。比如(年利1.5%):

第5天存入5000,第45天存入5500,第90天结算:

  1. 利息 = ((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

更进一步

  • 查看当前所有账户的总金额
    • 使用静态数据和静态函数
  • 修改日期表示方式
    • 创建一个日期类型

代码实现

CPP课程综合实例 - 图2

SavingsAccount.h

  1. #ifndef SAVINGS_ACCOUNT_H
  2. #define SAVINGS_ACCOUNT_H
  3. #include <string>
  4. #include "Date.h"
  5. using namespace std;
  6. class SavingsAccount
  7. {
  8. private:
  9. static double total;
  10. string id;
  11. double balance;
  12. double rate;
  13. double accumulation;
  14. Date date;
  15. void record(Date date, double amount);
  16. public:
  17. SavingsAccount() = default;
  18. SavingsAccount(string id, double balance,Date date , double rate = 0.015);
  19. ~SavingsAccount();
  20. void show() const;
  21. string getId() const;
  22. double getBlance() const;
  23. double getRate() const;
  24. void deposit(Date date , double amount);
  25. void withdraw(Date date, double amount);
  26. void settle(Date date);
  27. void accumulate(Date date);
  28. static double getTotal();
  29. };
  30. #endif

Savings_account.cpp

  1. #include "SavingsAccount.h"
  2. #include "Date.h"
  3. #include <string>
  4. #include <iostream>
  5. #include <cmath>
  6. using namespace std;
  7. using SA = SavingsAccount;
  8. double SA::total = 0.0;
  9. void SA::record(Date date, double amount){
  10. accumulate(date);
  11. this->date = date;
  12. balance += amount;
  13. total+=amount;
  14. }
  15. SA::SavingsAccount(string id, double balance,Date date, double rate):
  16. id(id),balance(balance),rate(rate),
  17. date(date),accumulation(0){
  18. total += balance;
  19. }
  20. SA::~SavingsAccount(){}
  21. string SA::getId() const{ return id;}
  22. double SA::getBlance() const{ return balance;}
  23. double SA::getRate() const{return rate;}
  24. double SA::getTotal(){ return total;}
  25. void SA::show() const{
  26. cout.width(10);
  27. cout<<id;
  28. cout.width(10);
  29. cout<<accumulation;
  30. cout.width(10);
  31. cout<<balance<<"("<<rate<<")"<<endl;
  32. }
  33. void SA::deposit(Date date , double amount){
  34. this->record(date,amount);
  35. show();
  36. }
  37. void SA::withdraw(Date date, double amount){
  38. if(amount>balance)
  39. cout<<"取款失败,透支了"<<endl;
  40. else
  41. this->record(date,-amount);
  42. show();
  43. }
  44. void SA::settle(Date date){
  45. accumulate(date);
  46. this->date = date;
  47. double change = floor(accumulation*rate/365*100 +0.5)/100;
  48. total+= change;
  49. balance+=change;
  50. accumulation = 0;
  51. show();
  52. }
  53. void SA::accumulate(Date date){
  54. accumulation += floor((date - this->date)*balance*100 + 0.5)/100;
  55. }

main_SA.cpp

  1. #include <iostream>
  2. #include <string>
  3. #include "SavingsAccount.h"
  4. using namespace std;
  5. using SA = SavingsAccount;
  6. int main(){
  7. SA myAcc[] = {SA("PA001",0.0,Date(2020,1,10)),
  8. SA("PA399",0.0,Date(2020,4,30))};
  9. myAcc[1].deposit(Date(2020,1,15),5000);
  10. myAcc[1].deposit(Date(2020,2,24),5500);
  11. myAcc[1].settle(Date(2020,4,9));
  12. myAcc[0].deposit(Date(2020,5,5),2000);
  13. myAcc[0].settle(Date(2020,12,20));
  14. cout<<SA::getTotal()<<endl;
  15. cout<<Date(2020,4,9) - Date(2020,3,10)<<endl;
  16. return 0;
  17. }

Date.h

  1. #ifndef DATE_H
  2. #define DATE_H
  3. class Date
  4. {
  5. private:
  6. int year;
  7. int month;
  8. int day;
  9. bool falg_run;
  10. public:
  11. Date(int year, int month, int day);
  12. ~Date() = default;
  13. int operator-(const Date &d);
  14. bool isRun(int y);
  15. };
  16. #endif

Date.cpp

  1. #include "Date.h"
  2. int Month_nor[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  3. int Month_run[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  4. Date::Date(int year, int month , int day):year(year),month(month),day(day){
  5. falg_run = isRun(year);
  6. }
  7. int Date::operator-(const Date & d){
  8. int result = 0;
  9. result += day;result -= d.day;
  10. for(int i = 1 ; i< month;++i)
  11. falg_run? result+=Month_run[i]:result+=Month_nor[i];
  12. for(int i = 1 ; i<d.month;++i)
  13. d.falg_run?result-=Month_run[i]:result-=Month_nor[i];
  14. for(int i = d.year ; i< year; ++i){
  15. isRun(i)?result+=366:result+=365;
  16. }
  17. return result;
  18. }
  19. bool Date::isRun(int year){
  20. if((year%400) || !(year%100)&&(year%4) )
  21. return true;
  22. return false;
  23. }

二、增加信用账户

这里使用类的继承与派生相关知识,用来新增一个信用卡账户。

image-20200330165155536.png

需求说明

信用卡账户特点

  1. 允许透支和信用额度
  2. 利息:存钱没有利息,透支超过免息期会有利息(暂不考虑)。
  3. 结算一月一次,假定每月1日
  4. 每年交一次年费,假定1月1日

输出格式

账户创建信息

流水:日期 账户 交易金额 余额 备注

最后输出:每个账户的余额 + 信用卡的额度

所有账户的总余额 (扣除信用卡欠款)

程序实现

CPP课程综合实例 - 图4 代码不多,但是复杂的文件系统让人头晕。这里面最关键的就是数据成员被封装之后,不知道某个数据存到哪里去了。子类之间跟共同基类如何协调。我觉得需要更加清晰的图示。

image-20200331163609091.png

所以接下来的代码可能会转移到vs中编写。

三、虚函数统一接口

增加交互要求:

image-20200401121045735.png

image-20200401121105517.png

通过一个基类指针和可以实现不同账户的不同动作

通过一个指针数组就可以保存不同的账户

代码完成不再赘述,最后工程文件会上传到仓库

四、容器模板

用vector容器存储对象

用map存储历史记录

五、IO

用本地文件存储历史记录

六、异常

异常状况捕捉