IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 清华大学C++程序设计(郑莉)综合实践 -> 正文阅读

[C++知识库]清华大学C++程序设计(郑莉)综合实践

清华大学C++程序设计(郑莉)综合实践


前言

课程综合实践中实现了模拟银行,用户可以添加储蓄类和信用卡类账户,并且对账户进行存取款操作,其中储蓄类账户每年一月一日结算,信用卡类账户每月一日结算。


一、头文件

1.date.h

该类用来记录程序中的时间,用户可以输入xxxx-xx-xx的格式,为其他类提供计算两日期间相差天数的方法。

#pragma once
#ifndef _DATE_H_
#define _DATE_H_
#include<iostream>
#include<utility>
#include<string>
using namespace std;
class Date {
private:
	int year;
	int month;
	int day;
	int totalDays;//从公元元年1月1日开始的第几天
public:
	Date(int year, int month, int day);
	Date() :year(0), month(0), day(0), totalDays(0) { ; }
	inline int getYear() const { return year; }
	inline int getMonth() const { return month; }
	inline int getDay()const { return day; }
	inline int getMaxDay() const;
	bool isLeapYear() const;
	void show() const;
	int operator-(const Date& date) const {
		return this->totalDays - date.totalDays;
	}
	//重载<
	bool operator< (const Date& date) const {
		if (this->getYear() == date.getYear()) {
			if (this->getMonth() == date.getMonth()) {
				return this->getDay() < date.getDay();
			}
			return this->getMonth() < date.getMonth();
		}
		return this->getYear() < date.getYear();
	}
	//重载输入流
	friend istream& operator >> (istream& in, Date& date);
	//重载输出流
	friend ostream& operator << (ostream& out, Date& date);
	int getCurMonDay() const;//获得当前月的天数
};
#endif // _DATE_H_

2.accumulator.h

该类是用来处理结算利息的辅助工具类。

#pragma once
#ifndef _ACCUMULATOR_H_
#define _ACCUMULATOR_H_
#include"date.h"
class Accumulator {
private:
	Date lastDate;
	double value; //账户中的金额数
	double sum;//上一次日期前的按日累加和
public:
	Accumulator(Date date,double value);
	double getSum(Date date) const;
	void change(Date date, double value);
	void reset(Date date, double value);
};
#endif // _ACCUMULATOR_H_

3.account.h

储蓄账户和信用卡账户的基类,其中有二者相同的元素。并在其中写入了Detail详情信息类,该类存储查询得到的相关信息,在multimap中存储用于使用时间范围查询流水信息,multimap以date为键详情信息为值,故在上述date类中需要重载<号以便满足键值对在map中有序。

#ifndef _ACCOUNT_H_
#define _ACCOUNT_H_
#include<iostream>
#include<map>

#include"date.h"
using namespace std;
//操作详情信息
class Detail {
private:
	string id;
	Date da;
	double v, all;
	string desc;
public:
	Detail(string id,Date da, double v, double all, string desc) :id(id),da(da), v(v), all(all), desc(desc) {

	}
	void show() const{
		cout << "账号:" << id << "\t";
		da.show();
		cout << "\t" << v << "\t" << all << "\t" << desc << endl;
	}
};
typedef multimap<Date, Detail> RecordMap;//定义存储账目记录的多重映射
class Account {
private:
	string id;//账号
	double balance;//余额
	static double total;//所有账户的总金额
	static RecordMap mp;//静态成员,全局仅有一份
public:
	//构造函数
	Account(Date date, string id);
	inline string getId() const { return id; }
	inline double getBalance() const { return balance; }
	inline static double getTotal() { return total; }
	void record(Date date, double amount, const string& desc);
	//显示账户信息
	virtual void show() const {
		cout << " " << getId() << "\t" << "Balance:" << getBalance() << endl;
	};
	virtual void deposit(Date date, double amount, const string& desc) = 0;
	virtual void withdraw(Date date, double amount, const string& desc) = 0;
	virtual void settle(Date date) = 0;//纯虚函数,定义在派生类给出,方便用基类指针指向不同解决方法
	void error(string msg) const;
	//静态成员函数,时间范围查询
	static void serach_find(const Date &date1, const Date &date2);
};
#endif

4.savingsaccount.h

该类是储蓄账户类,包含对储蓄账户的创建和存取款操作。

#pragma once
#ifndef _SAVINGSACCOUNT_H_
#define _SAVINGSACCOUNT_H_
#include<iostream>
#include"date.h"
#include"account.h"
#include"accumulator.h"
using namespace std;
class savingsAccount :public Account {
private:
	Accumulator acc;//辅助工具类
	double rate;//利率
public:
	savingsAccount(Date date, string id, double rate);
	double getRate() const { return rate; }
	void deposit(Date date, double amount, const string &desc);//存钱
	void withdraw(Date date, double amount, const string &desc);//取钱
	void settle(Date date);//利息结算
};
#endif // !_SAVINGSACCOUNT_H_

5.creditaccount.h

该类是信用卡账户类,包含对信用卡账户的创建和存取款操作。

#pragma once
#ifndef _CREDITACCOUNT_H_
#define _CREDITACCOUNT_H_
#include<iostream>
#include"account.h"
#include"accumulator.h"
#include"date.h"
using namespace std;
class creditAccount :public Account{
private:
	Accumulator acc;
	double credit, rate, fee;//信用额,利息,卡费
	//查询债务
	double getDebt() const {
		return getBalance() < 0 ? getBalance() : 0;
	}
public:
	creditAccount(Date date, 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;
	void deposit(Date date, double amount, const string &desc);
	void withdraw(Date date, double amount, const string &desc);
	void settle(Date date);//每月1日调用一次
	void show() const;
};
#endif // !_CREDITACCOUNT_H_

二、实现文件

1.date.cpp

其中totalDays的计算方法是,每次初始化对象时,计算当前存入日期到元年1月1日的日子数,365*(year-1)表示除当前年外所有年的日子总数(平年)然后加上这段时间出现的所有闰年数,(year-1)/4+(year-1)/400-(year-1)/100,普通年每四年一闰,世纪年每400年一闰,最后加上当前年的天数。

#include"date.h"
#include<cstdlib>//包含exit函数
namespace {//namespace使下面的定义只在当前文件中有效
	//存储平年中某个月1日前有多少天,方便getmaxday函数实现
	const int DAYS_BEFORM_MONTH[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
	const int DAYS[]{ 0,31,28,31,30,31,30,31,31,30,31,30,31 };
};

Date::Date(int year, int month, int day):year(year),month(month),day(day) {
	if (isLeapYear() && month == 2) {
		if (day <= 0 || day > 29) {
			cout << "Invalid date:";
			show();
			cout << endl;
			exit(1);
		}
	}
	if (day <= 0 || day > DAYS[month]) {
		cout << "Invalid date:";
		show();
		cout << endl;
		exit(1);
	}
	totalDays = 365 * (year - 1) + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + getMaxDay() + day - 1;//当前日期到元年1月1日的日子数
	//show();
	//cout << "当前距离元年有" << totalDays << endl;
}
int Date::getMaxDay() const {
	if(isLeapYear()&&month>1)
		return DAYS_BEFORM_MONTH[month]+1;
	return DAYS_BEFORM_MONTH[month];
}
int Date::getCurMonDay() const {
	return DAYS[this->month];
}
bool Date::isLeapYear() const {
	if ((!(year % 4) && (year % 100)) || !(year % 400))	return true;//能被4整除但不能被100整除,或者能被400整除
	return false;
}
void Date::show() const {
	cout << year << "-" << month << "-" << day << "\t";
}
istream& operator >> (istream& in, Date& date) {
	char ch;
	in >> date.year ;
	in >> ch;//去掉-
	in >> date.month;
	in >> ch;
	in >> date.day;
	return in;
}
ostream& operator << (ostream& out, Date& date) {
	out << date.year << "-" << date.month << "-" << date.day;
	return out;
}

2.accumulator.cpp

在其他类中会经常调用以下函数。

#include"accumulator.h"
Accumulator::Accumulator(Date date, double value):lastDate(date),value(value),sum(0){

}
//返回指定日期的按日累加值
double Accumulator::getSum(Date date) const {
	//cout << "时间间隔:" << (date - lastDate) << " 累加和:" << sum + value * (date - lastDate) << endl;
	return sum + value * (date - lastDate);
}
//改变数值
void Accumulator::change(Date date, double value) {//value是账户中的金额数
	sum = getSum(date);//计算该日期前的按日累加值
	lastDate = date;//修改最后日期
	this->value = value;//改变当前值
}
void Accumulator::reset(Date date, double value) {
	lastDate = date;
	this -> value = value;
	sum = 0;
}

3.account.cpp

其中在账户信息发生变化时都会调用record函数,在该函数中向map加入每次变化的详情信息,方便以后查询。

#include"account.h"
double Account::total = 0;
RecordMap Account::mp ;
Account::Account(Date date, string id)
	:id(id), balance(0) {
	cout << date << "\t" << "#" << id << " is created " << endl;

}
void Account::record(Date date, double amount, const string &desc) {
	//当余额发生变动时,更新余额累加值
	amount = floor(amount * 100 + 0.5) / 100;//保留2位小数
	balance += amount;
	total += amount;
	date.show();
	cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl;
	//存入详情信息结构体作为值
	// date作为键
	Account::mp.emplace(date, Detail(id,date,amount, balance,desc));

}
void Account::error(string msg) const {

		cout << "当前错误信息为:" << msg << endl;
} 
void Account::serach_find(const Date& date1, const Date& date2) {
	auto start = Account::mp.lower_bound(date1);//找到第一个大于等于该日期的详情信息
	auto over = Account::mp.upper_bound(date2);//找到第一个大于该日期的详情信息
	for (; start != over; start++) {
		start->second.show();
	}
}

4.savingsaccount.cpp

该类是储蓄账户类,包含对储蓄账户的创建和存取款操作,储蓄账户每年一月一日结算利息。

#include"savingsaccount.h"
#include"accumulator.h"
savingsAccount::savingsAccount(Date date, string id, double rate) :Account(date,id), rate(rate),acc(Accumulator(date,0)) {//调用基类的构造函数构造
	//cout << "#\t" << id << "\t" << "储蓄账户创建完成" << endl;
}

void savingsAccount::deposit(Date date, double amount, const string& desc) {//存款
	record(date, amount, desc);
	acc.change(date, getBalance());//将工具类中value改为账户中金额数
}

void savingsAccount::withdraw(Date date, double amount, const string& desc) {
	if (amount <= getBalance()) {
		record(date, -amount, desc);
		acc.change(date, getBalance());
		
	}
	else {
		cout << "您的账户余额不足!" << endl;
	}
}

void savingsAccount::settle(Date date) {
	const double interest = acc.getSum(date) * rate / 365;//年息
	if (interest != 0 && date.getMonth() == 1 && date.getDay() == 1) {//储蓄账户每年一月结算
		record(date, interest, "利息");
	}
	acc.reset(date, getBalance());//从新计算累加值
}

5.creditaccount.cpp

该类是信用卡账户类,包含对信用卡账户的创建和存取款操作,利息结算每月一次。

#include"creditaccount.h"
//构造函数
creditAccount::creditAccount(Date date, string id, double credit, double rate, double fee) :
	Account(date, id), credit(credit), rate(rate), fee(fee), acc(Accumulator(date, 0)) {
	//cout << "#\t" << id << "\t" << "信用卡账户创建完成" << endl;
}
//得到可用信用额
double creditAccount::getAvailableCredit() const {
	if (getBalance() < 0) {
		return credit + getBalance();//存在负债,返回信用额减去负债
	}
	return credit;
}
//存钱没利息
void creditAccount::deposit(Date date, double amount, const string& desc) {
	record(date, amount, desc);
	acc.change(date, getDebt());
}
//取钱有利息
void creditAccount::withdraw(Date date, double amount, const string& desc) {
	if (amount <= getAvailableCredit()) {
		record(date, -amount, desc);
		acc.change(date, getDebt());
	}
	else {
		cout << "余额不足" << endl;
	}
}

void creditAccount::settle(Date date) {
	const double interest = acc.getSum(date) * rate;//月息
	if (interest != 0 && getAvailableCredit() > -interest) {
		record(date, interest, "利息");
	}
	//每年一月收信用卡卡费
	if (date.getMonth() == 1 && getAvailableCredit() > fee) {
		record(date, -fee, "卡费");
	}
	acc.reset(date, getBalance());//从新计算累加值
}
void creditAccount::show() const {
	cout << " " << getId() << "\t" << "Balance:" << getBalance() << "\t" << "当前信用卡余额:" << getAvailableCredit() << endl;
}

三、main方法

在main方法中调用以上类进行测试,并将每次输入的命令存入txt文件中。

#include"account.h"
#include"savingsaccount.h"
#include"accumulator.h"
#include"date.h"
#include"creditaccount.h"
#include<vector>
#include<fstream>
using namespace std;
int main() {
    ofstream fout("data.txt");//写入
    Date date(2008, 11, 1);//初始时间节点,每次时间更改需要更新,应该先从备份文件中读取时间节点
    vector<Account*> accounts;
    Account* acc;
    std::cout << "操作:(a)增加用户,(d)存款,(w)取款,(s)查询账户信息,(c)快进,(n)进入下个月,(q)查询日期区间所有记录,(e)退出" << endl;
    while (1) {
        std::cout << date << "\t Total:" << Account::getTotal() << "\t command> ";
        char str;
        cin >> str;
        if (str == 'a') {//增加用户
            char type;
            string id;
            cin >> type >> id;//账户类型,s表示储蓄账户,c表示信用卡账户
            if (type == 's') {
                double rate;
                cin >> rate;
                acc = new savingsAccount(date, id, rate);
                fout << str << " " << type << " " << id << " " << rate << endl;
                //cout << str << " " << id << " " << type << " " << rate << endl;
            }
            else {
                double credit, fee,rate;
                cin >> credit >> rate >> fee;
                acc = new creditAccount(date, id, credit, rate, fee);
                fout << str << " " << type << " " << id << " " << credit << " " << rate << " " << fee << endl;
            }
            accounts.push_back(acc);
        }
        else if (str == 'd') {//存款:读入账户id,存款金额
            int idx;
            double amount;
            string desc;
            cin >> idx >> amount;
            std::getline(cin, desc);//读取一行
            if (idx >= 0 && idx < accounts.size()) {//检验下标合法性
                accounts[idx]->deposit(date, amount, desc);
            }
            else {
                std::cout << "没有找到该账户,请重试" << endl;
            }
            fout << str << " " << idx << " " << amount << " " << desc << endl;
        }
        else if (str == 'w') {//取钱,读入id,取款金额
            int idx;
            double amount;
            string desc;
            cin >> idx >> amount;
            std::getline(cin, desc);
            if (idx >= 0 && idx < accounts.size()) {//检验下标合法性
                accounts[idx]->withdraw(date, amount, desc);
            }
            else {
                std::cout << "没有找到该账户,请重试" << endl;
            }
            fout << str << " " << idx << " " << amount << " " << desc << endl;
        }
        else if (str == 's') {//查询所有账户信息
            for (int i = 0; i < accounts.size(); i++) {
                std::cout << "[" << i << "]" << "\t";
                accounts[i]->show();
            }
        }
        else if (str == 'c') {//改变日期,读入快进到第几天,不能回退不能超过本月最大日期,更改时间节点
            int day;
            cin >> day;
            if (day < date.getDay()) {
                std::cout << "不能输入之前的日期" << endl;
            }
            else if(day>date.getCurMonDay()){
                std::cout << "不能输入超过月份的日子" << endl;
            }
            else {
                date = Date(date.getYear(), date.getMonth(), day);
            }
            fout << str << " " << day << endl;
        }
        else if (str == 'n') {//进入下一个月,当前为12时,进入下一年,每年一月一号计算储蓄账户利息,更改时间节点
            if (date.getMonth() == 12) {
                date = Date(date.getYear() + 1, 1, 1);//进入新年1月1日

            }
            else {
                date = Date(date.getYear(), date.getMonth() + 1, 1);//进入下个月1日
            }
            for (auto it = accounts.begin(); it != accounts.end(); it++)   (*it)->settle(date);//信用卡账户每月结算,储蓄账户每年结算
            fout << str << endl;
        }
        else if (str == 'q') {//查询范围内详情信息
            Date date1, date2;
            cin >> date1 >> date2;
       
            if (date2 < date1) {
                std::cout << "第二个日期必须大于第一个日期,请重新输入" << endl;
            }
            else if (date1.getMonth() <= 0 || date1.getMonth() > 12 || date2.getMonth() <= 0 || date2.getMonth() > 12) {
                std::cout << "请输入合法日期" << endl;
            }
            else if (date1.getDay() > date1.getCurMonDay() || date2.getDay() > date2.getCurMonDay()) {
                std::cout << "请输入合法日期" << endl;
            }
            else {
                Account::serach_find(date1, date2);//输入两个日期(xxxx-xx-xx)中间空格隔开
            }
            fout << str << " " << date1 << " " << date2 << endl;
        }
        else if (str == 'e') {//退出程序
            break;
        }
    }
    fout.close();
    std::cout << "结束时时间为:";
    std::cout << date << endl;
    std::cout << "Total: " << Account::getTotal() << endl;
    return 0;
}

总结

对清华大学C++程序设计中的综合实践做一个总结,其中实现细节可能与课中展示有所不同,若发现其中存在问题欢迎指出一起讨论。最后的十一十二章内容没有全部实现,例如创建一个Date类对象失败程序怎么继续运行下去等异常处理问题。
计划下一步实现在Linux上搭建服务器接收Windows客户端传入的命令,然后服务端处理,最后返回结果在客户端上。
项目全部代码可以在Github仓库获取(欢迎start)!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-11 23:48:36  更:2022-01-11 23:50:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:29:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码