C++实现简单银行管理系统代码详解

银行管理系统

开源注释详解:Github

功能

  • 添加账户
    • 储蓄账户
    • 信用卡账户
  • 存款
  • 取款
  • 当前账户余额
  • 指定时间内的账目信息
    • 利息
  • 本地化存储,二次启动同步
  • 所有账户总金额
  • 退出

数据存储思路

将每次运行的代码存储到本地txt文件当中,每次启动可以首先初始化文件内容,已达到文件储存的目的

缺点

  • 数据量过大数据初始化难
  • 业务逻辑越复杂也越难以保存
  • 用户交互需要按照文件保存书写指令,十分不便

或许可以使用MySQL数据库存储数据,用C++与MySQL进行交互,达到相关查询,存储的功能。

类图呈现

银行管理系统类关系图

各文件功能

  • date.h 日期类头文件
  • date.cpp 日期类实现文件
  • account.h 账户类定义头文件
  • account.cpp 账户类实现文件以及记录
  • accumulator.h 对数据进行累加的相关计算
  • main.cpp 主函数文件
  • Array.h 数组模版的头文件
  • Controller类保存账户列表,当前日期和处理指定命令

详解源代码

date.h

#pragma once
/*日期类头文件,对日期类文件进行处理*/
#ifndef _DATE_H_
#define _DATE_H_
#include <iostream>
class Date   //日期类
{
private:
	int year;  //年
	int month; //月
	int day;  //日
	int totalDays; //该日期是从公元元年1月1日开始的第几天
public:
	Date(int year=1, int month=1, int day=1); //用年,月,日构造日期
	//专门从cin读入一个日期,赋值查询历史账目功能
	//static Date read();
	

	//获取Date日期年份
	int getYear() const
	{
		return year;
	}
	//获取Date日期月份
	int getMonth() const
	{
		return month;
	}
	//获取Date日期天
	int getDay() const
	{
		return day;
	}
	//获取Date当月的天数
	int getMaxDay() const; 
	// 判断Date日期是否是闰年
	bool isLeapYear() const  //判断是否为闰年
	{
		return year % 4 == 0 && year * 100 != 0 || year % 400 == 0;
	}
	//输出Date日期
	void show() const; 
	//输出Data从公元元年1月1日到目前date的天数
	int distance(const Date& date) const
	{
		return totalDays - date.totalDays;
	}
	//重载Date之前的“-”号,用公元元年到目前的日期相减
	int operator-(const Date& date) const
	{
		return totalDays - date.totalDays;
	}
	//重载Date之间的“<"号,用永远元年到目前date的日期计算
	bool operator<(const Date& date) const
	{
		return totalDays < date.totalDays;
	}
};
//重载Date类输入,格式化日期格式:year-month-day
std::istream& operator >>(std::istream& in, Date& date);
//重载Date类输出,格式化日期格式:year-month-day
std::ostream& operator<<(std::ostream& out, const Date& date);
#endif // !_DATE_H_

date.cpp

/*日期类实现函数*/
#include "date.h"
#include <iostream>
#include <cstdlib>
#include <stdexcept>  //标准库表头,此头文件是错误处理库的一部分
using namespace std;
namespace  //使用namespace使下面的定义只能在当前文件中有效
{
	//存储平年中每个月1日之前有多少天,为便于getMaxDay函数的实现,
	const int DAYS_BEFORE_MONTH[] = { 0,31,59,90,120,151,181,212,143,273,304,334,365 };
}

Date::Date(int year, int month, int day) :year(year), month(month), day(day)
{
	if (day <= 0 || day > getMaxDay())
	{
		throw runtime_error("Invalid date"); //Date发生异常,直接使用标准程序库构造异常抛出
	}
	//减一是为了计算总天数,会加上月份和天数,年份日要减一
	int years = year - 1;
	//计算总天数
	totalDays = years * 365 + years / 4 - years / 100 + years / 400 + DAYS_BEFORE_MONTH[month - 1] + day;
	//如果是瑞年并且月份大约2,总天数+1
	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];
	}
}
//输出Date的年-月-日
void Date::show() const
{
	cout << getYear() << "-" << getMonth() << "-" << getDay();
}
istream& operator>>(istream& in, Date& date) //istream通用输入流
{
	int year, month, day;
	char c1, c2;
	cout << "类似输入格式为:2019-01-01" << endl;
	in >> year >> c1 >> month >> c2 >> day;
	//对输入进行判断,若没有按照格式,返回错误
	if (c1 != '-' || c2 != '-')
		//可用于运行时检测的异常类
		throw runtime_error("Bad time format"); 

	//将所得的正确日期返回给date,指针
	date = Date(year, month, day);

	//返回用户的输入 此处
	return in;  
}
//虫重载输出流,使date按照标准格式输出
ostream& operator << (ostream& out, const Date& date) //ostream通用输出流
{
	out << date.getYear() << "-" << date.getMonth() << "-" << date.getDay();
	return out;
}

account.h

#pragma once
/*银行账户类头文件*/
#ifndef _ACCOUNT_H_
#define _ACCOUNT_H_
#include "date.h"
#include "accumulator.h"
#include <string>  //字符串头文件
#include <istream>
#include <map>  //引出关联容器
#include <stdexcept>
//前置声明
class Account;
//账目记录类
class AccountRecord
{
private:
	//日期
	Date date;
	//账户
	const Account* account; 
	// 账户金额
	double amount;
	// 余额
	double balance;
	//描述
	std::string desc;
public:
	//构造函数
	AccountRecord(const Date& date, const Account* account, double amount, double balance, const std::string& desc);
	//输出当前记录
	void show() const;
};

// 创建关联容器,建立日期和账户记录类的已排序列表
typedef std::multimap<Date, AccountRecord>RecordMap;
//账户父类
class Account
{
public:
	std::string id; //账户Id字符串
	double balance;  //账户余额
	static double total;  //所有账户的总金额静态变量
	static RecordMap recordMap;  //账目记录
protected:
	//提供派生类调用的构造函数:日期,id为账户
	Account(const Date& date, const std::string& id);
	//记录一笔账,date为日期,amount为金额,desc为说明
	void record(const Date& date, double amount, const std::string& desc);
	//报告错误信息
	void error(const std::string& msg) const;
public:
	//获取账户id
	const std::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 std::string& desc) = 0;
	//纯虚函数,没有具体的操作内容,要求各派生类根据需要定义自己的版本
	//取出现金,date为日期,amount为金额,desc为款项说明
	virtual void withdraw(const Date& date, double amount, const std::string& desc) = 0;
	//结算(计算利息、年费等),每月结算一次,date为结算日期
	virtual void settle(const Date& date) = 0;
	//显示账户信息
	virtual void show(std::ostream& out) const;
	//查询指定时间内的账目记录,开始Date,结束Date
	static void query(const Date& begin, const Date& end);

	
};
//内联重载: 将Account输出调用Account.show()
inline std::ostream& operator<<(std::ostream& out, const Account& account)
{
	account.show(out);
	return out;
}

class SavingsAccount : public Account  //存储账户类
{
private:
	Accumulator acc;  //辅助计算利息的累加器
	double rate;	//存款的年利率
public:
	//储蓄账户,日期Date,账户Account的id,存款利率
	SavingsAccount(const Date &date, const std::string &id, double rate);
	//获取储蓄账户的存款利率
	double getRate() const
	{
		return rate;
	}
	// 存钱: 参数: 日期Date,金额,描述信息
	void deposit(const Date &date, double amount,const std::string &desc);// 存入现金
	//取款:参数: 日期Date,金额,描述信息
	void withdraw(const Date &date, double amount,const std::string &desc);//取出现金
	//结算利息:参数:Date日期
	void settle(const Date &date);
};
class CreditAccount : public Account  //信用账户类
{
private:
	Accumulator acc; //辅助计算利息的累加器
	//信用额度
	double credit;  
	double rate;  //欠款的日利率
	double fee;   //信用卡年费
	//获取欠款额
	double getDebt()   
	{ 
		//获取账户Account的余额,
		double balance = getBalance();  
		//如果余额大于0不欠钱,返回0,否则返回balance
		return (balance < 0 ? balance : 0);
	}
public:  //构造函数
	//信用卡类:参数:日期Date,账户Account:id,信用额度,欠款日利率,信用卡年费
	CreditAccount(const Date& date, const std::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;
	}
	//存入现金:参数:日期Date,账户Account金额,存款描述
	void deposit(const Date& date, double amount, const std::string& desc);
	//取出现金,参数:取款日期Date,取款金额,取款描述
	void withdraw(const Date& date, double amount, const std::string& desc);
	//结算利息和年费,参数Date日期
	void settle(const Date& date);//结算利息和年费,每月1号调用一次该函数
	// 输出账户id,账户金额,账户余额
	void show() const;
	//虚函数输出
	virtual void show(std::ostream& out) const;
};
//账户异常处理类
class AccountException :public std::runtime_error
{
private:
	// 账户
	const Account* account;
public:
	//传递运行中的异常信息,以及账户Account类
	AccountException(const Account* account, const std::string& msg)
		:runtime_error(msg), account(account)
	{

	}
	//获得异常账户类
	const Account* getAccount() const
	{
		return account;
	}
};
#endif //_ACCOUNT_H_

account.cpp

/*
project :Account账户类实现文件cpp
*/
#include "account.h"
#include <iostream>
#include <cmath>
#include <utility>
using namespace std;
using namespace std::rel_ops;
//AccountRecord类的实现:参数日期Date,账户Account类,金额,余额,描述信息
AccountRecord::AccountRecord(const Date& date, const Account* account, double amount, double balance, const std::string& desc)
	:date(date), account(account), amount(amount), balance(balance), desc(desc)
{

}
// 展现出账户记录类的账户时间,Id,存款金额,余额(算上信用卡),描述信息
void AccountRecord::show() const
{
	//date.show();
	cout <<date<< "\t#" << account->getId() << "\t" << amount << "\t" << balance << "\t" << desc << endl;
}




//存款总金额全局变量(所有账户)
double Account::total = 0;
// Account类中的账户记录
RecordMap Account::recordMap;





//Account账户类构造函数
Account::Account(const Date& date, const string& id)
	:id(id), balance(0)
{
	//date.show();
	cout << date<<"\t#" << id << " created" << endl;
}
//记账:参数:Date时间,amount金额,记账描述
void Account::record(const Date& date, double amount, const string& desc)
{

	amount = floor(amount * 100 + 0.5) / 100;  //保留小数点后两位,
	balance += amount; //余额增加
	total += amount;  //账户总额增加
	//date.show();  //输出时间
	//将添加的数据存入账目记录类
	AccountRecord record(date, this, amount, balance, desc);
	//将数据插入到关联容器内部,,date为主键 
	recordMap.insert(make_pair(date, record));
	record.show();
	//cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl;
}
//显示账户信息
void Account::show(ostream &out) const
{
	cout << "#" << id << "\tBalance:" << balance;
}


//SavingsAccount类的实现,参数:Date时间,Account的ID,利率
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); //记录一笔账
	//调佣accumulator函数,更新值,变更当前的时间,还有值
	acc.change(date, getBalance());
}
//取钱
void SavingsAccount::withdraw(const Date& date, double amount,const string& desc)
{
	if (amount > getBalance())
	{
		cout << "Error: not enough money" << endl;
	}
	else
	{
		record(date, -amount, desc);
		acc.change(date, getBalance());
	}
		
}
// 计算利息:传递时间Date
void SavingsAccount::settle(const Date& date)
{
	double interest = acc.getSum(date) * rate / date.distance(Date(date.getYear()-1,1,1)); //计算年息
	if (interest != 0)
	{
		//将利息记账
		record(date, interest,"interest");
	}
	//初始化,日期,数值,累加器清零
	acc.reset(date, getBalance());
}
//CreditAccount 类默认构造函数的实现
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("nt enough credit");
	}
	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(ostream& out) const
{
	Account::show(out);
	cout << "\tAvailable credit:" << getAvailableCredit();
}


//异常
void Account::error(const string& msg) const
{
	throw AccountException(this, msg);
}

//账户记录查询实现,参数:开始Date,结束Date
void Account::query(const Date& begin, const Date& end)
{
	//从开始到结尾遍历输出
	if (begin <= end)
	{
		//lower_bound返回指向首个不小于给定键的元素的迭代器
		RecordMap::iterator iter1 = recordMap.lower_bound(begin);
		//upper_bound返回指向首个大于给定键的元素的迭代器
		RecordMap::iterator iter2 = recordMap.upper_bound(end);
		for (RecordMap::iterator iter = iter1; iter != iter2; ++iter)
		{
			iter->second.show();
		}
	}
}

accumulator.h

/*将accumulation.h按日将数字累加的Accumulatior类的头文件*/
#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.distance(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 // !_ACCUMULATOR_H_

main.cpp

/*
Project:存款类主函数文件
environment:Visual studio 2022
*/
#include "account.h"
#include "Array.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <string>

using namespace std;
//释放空间结构体,用于析构函数
struct deleter
{
	template<class T>void operator() (T* p)
	{
		delete p;
	}
};

//建立类,用来存储账户列表和处理命令
class Controller
{
private:
	Date date;  //当前日期
	vector<Account*>accounts; //账户列表
	bool end;  //用户是够输入了退出命令
public:
	//存储用户数据,参数:Date时间
	Controller(const Date& date) :date(date), end(false)
	{

	}
	//析构函数
	~Controller();
	//返回当前的时间
	const Date& getDate() const
	{
		return date;
	}
	//bool值,返回是否结束
	bool isEnd() const
	{
		return end;
	}
	//执行一条命令,返回该命令是否改变了当前状态(即是否需要保存该命令)
	bool runCommand(const string& cmdLine);
};
//释放从账户开始到结束的所有内存
Controller::~Controller()
{
	//for_each遍历:开始,结束,执行
	//按照顺序应用给定的函数对象f到接引到范围[first,last]中每个迭代器的结果
	for_each(accounts.begin(), accounts.end(), deleter());
}
bool Controller::runCommand(const string& cmdLine)
{
	/*
	* 指令内容
	* a s S3755217 0.015
	* a s 02342342 0.015
	* a c C5392394 10000 0.0005 50
	* c 5
	
	*/
	//读取是有顺序要求的,根据指针向后,异常赋值
	//第一个赋值给cmd判断进入那个case开面
	//后面根据不同case依次赋值
	istringstream str(cmdLine);
	char cmd, type;
	int index, day;
	double amount, credit, rate, fee;
	string id, desc;
	Account* account;
	Date date1, date2;
	str >> cmd;
	switch (cmd)
	{
	case 'a':	//增加账户
		str >> type >> id;
		if (type == 's')
		{
			str >> rate;
			account = new SavingsAccount(date, id, rate);
		}
		else
		{
			str >> credit >> rate >> fee;
			account = new CreditAccount(date, id, credit, rate, fee);
		}
		accounts.push_back(account);
		return true;
	case 'd':	//存入现金
		str >> index >> amount;
		getline(str, desc);
		accounts[index]->deposit(date, amount, desc);
		return true;
	case 'w':	//取出现金
		str >> index >> amount;
		getline(str, desc);
		accounts[index]->withdraw(date, amount, desc);
		return true;
	case 's':	//查询各账户信息
		for (size_t i = 0; i < accounts.size(); i++)
			cout << "[" << i << "] " << *accounts[i] << endl;
		return false;
	case 'c':	//改变日期
		str >> 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);
		return true;
	case 'n':	//进入下个月
		if (date.getMonth() == 12)
			date = Date(date.getYear() + 1, 1, 1);
		else
			date = Date(date.getYear(), date.getMonth() + 1, 1);
		for (vector<Account*>::iterator iter = accounts.begin(); iter != accounts.end(); ++iter)
			(*iter)->settle(date);
		return true;
	case 'q':	//查询一段时间内的账目
		str >> date1 >> date2;
		Account::query(date1, date2);
		return false;
	case 'e':	//退出
		end = true;
		return false;
	}
	cout << "Inavlid command: " << cmdLine << endl;
	return false;
}



int main(void)
{
	Date date(2022,11,1); //起始日期
	cout << "输出化本地化数据库数据" << endl;
	//	初始化命令
	Controller controller(date);
	string cmdLine;
	//打开文件名称
	const char* FILE_NAME = "commands.txt";
	ifstream fileIn(FILE_NAME); //以读模式打开文件

	if (fileIn) //直到执行到没有指令
	{	//如果正常打开,就执行文件中的每一条命令
		while (getline(fileIn, cmdLine))
		{
			try
			{
				controller.runCommand(cmdLine);
			}
			catch (exception& e)
			{
				cout << "Bad line in" << FILE_NAME << ":" << cmdLine << endl;
				cout << "Error:" << e.what() << endl;
				return 1;
			}
		}
			
		fileIn.close();	//关闭文件
	}
	//初始化指令结束

	//追加模式写入
	ofstream fileOut(FILE_NAME, ios_base::app);	//以追加模式
	//选择框
	cout << "\n\n\t\t***由于银行信息系统使用命令行存储数据形式,请严格按照输入格式进行输入:***" << endl;
	cout << "\t\t\t\t******命令选项*******"
		<<"\n\t\t\t\t\t(a)add account: a s S3755217 0.015      //a代表添加用户,s代表储蓄卡,c代表信用卡,S3755217为账户id,0.015为利率 "
		<<"\n\t\t\t\t\t(d)deposit    :d 0 5000 salary          //d代表存钱,0代表第0个账户,5000代表金额,salary为存储说明"
		<< "\n\t\t\t\t\t(w)withdraw : w 2 2000 buy a cell     //w为取钱,2代表第二个账户,2000金额,buy a cell说明"
		<<"\n\t\t\t\t\t(s)show      : s                        //查看账户"
		<< "\n\t\t\t\t\t(c)change day :c 15                   //c为改变日期,15为日 "
		<< "\n\t\t\t\t\t(n)next month :n                       //进入下一个月"
		<<"\n\t\t\t\t\t(q)query      :q 2022-11-01 2022-12-01   //遍历从11月1号到12月1号的账目数据"
		<<"\n\t\t\t\t\t(e)exit        :e                       //退出" 
		<< endl;
	while (!controller.isEnd())
	{	//从标准输入读入命令并执行,直到退出
		cout << controller.getDate() << "\tTotal: " << Account::getTotal() << "\t\t\t\t\ncommand> ";
		cout << "命令输入规范:" << endl;
		string cmdLine;
		//读入命令,和文件存储格式相同
		getline(cin, cmdLine);
		try
		{
			//执行命令
			if (controller.runCommand(cmdLine))
				//并记录文件内容
				fileOut << cmdLine << endl;	//将命令写入文件
		}
		catch (AccountException& e)
		{
			cout << "Erroe(#" << e.getAccount()->getId() << "):" << e.what() << endl;
		}
		catch (exception& e)
		{
			cout << "Error: " << e.what() << endl;
		}
		
	}
	return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值