1. 目的与要求
1、目的:
(1)熟练掌握 C++语言的基本知识和技能:
(2)掌握面向对象程序设计的基本思想和方法;(3)能够利用所学的面向对象基本知识和技能,解决简单应用的程序设计
2、基本要求:(1)利用面向对象的方法以及 C++的编程思想来完成系统的设计;(2)在设计的过程中,建立清晰的类层次:定义各个类,每个类中要有各自的数据和成员函数:运用面向对象(继承、派生及多态性)来实现系统功能。
(3)在系统的设计中,要有清晰的界面设计,同时采用文件进行读写操作。
3、创新要求: 在基本要求达到后,可进行创新设计。
2. 问题描述及功能要求
设计一个银行账户管理程序,账户的信息有账号(唯一)、姓名、余额、身份证号码单位、电话号码、地址等,允许用户进行如下操作:开户、销户、存款、取款、转账、查询,一个用户可以有多个户头,账户的数值没有上限。程序运行时,可以由用户选择进行何种操作,开户操作要求输入用户信息后自动获取账号,用户销户后账号被回收,并且该账号可以继续分配给其它账户,不允许用户透支,根据姓名或账号可以进行用户的信息查询,所有的账户信息应存放到一个文件中,可以随时的访问和更新。
程序应输入不少于 10 人的账户信息,应考虑到人员同名的情况。
3. 实现思路以及代码
1. Person
只能格式化的从文件中写入或读出数据,一个用户可以办多张银行卡,所以不能确定用户有几张卡,并且每张卡又有不同的余额,用一个Person类存人和卡的信息,每张卡都对应一个人(多对多),但是打印时可以将人的信息和卡的信息分开打印。这样处理容易删除,如果将人的信息和卡的信息用一对多的方法表示,那就必须再创建一个文件,对这个文件进行维护,非常麻烦,所以不建议一对多 代码如下:
//人和卡的信息
class Person
{
public:
string _name; //姓名
string _id; //身份证号码
string _pnumber; //电话号码
string _address; //地址
string _account; //账号
double _balance = 0.0; //余额
};
Person p_tmp; //用来接受数据
vector<Person> v_person; //保存数据
2. 创建账号
要求:用户销户后账号被回收,并且该账号可以继续分配给其它账户。
思路:用key-value来实现,key存账号,value存1或0(1表示未使用,0表示已使用)。必须先创建一个card.txt,向card.txt文件中写入账号,然后拿来使用,代码如下:
#define CARD "1000000000" //默认账号10位数
#define LENGTH 10
#define SIZE 1000 //默认写入1000个账号
void DataCreate()
{
FILE* pf = fopen("card.txt", "w"); //打开文件
if (pf == nullptr) //打开失败则返回
{
perror("fopen");
return;
}
map<string, int> m;
string s = CARD;
int n = SIZE;
while (n--)
{
m.insert(pair<string, int>(s, 1)); //插入map中
fprintf(pf, "%s %d\n", s.c_str(), 1); //顺便打印到文件中
int tmp = stoi(s);
++tmp;
s = to_string(tmp);
}
}
编译后就可以在main.cpp文件路径下看到card.txt文件,并且卡号写入成功。
这个函数是向文件中写入账号的,所以先运行一次,得到card.txt之后就不需要运行。
3. 初始化两个数组
从文件中读取数据。
map<string, int> card;存的是所有银行卡的卡号
Person p_tmp;存的是人的信息
//卡号是否使用
map<string, int> card;
//初始化
void cardInit()
{
FILE* pf = fopen("card.txt", "r");
if (pf == nullptr)
{
perror("DataInit fopen");
return;
}
pair<string, int> tmp;
char s[LENGTH + 1];
int n = 0;
while (fscanf(pf, "%s %d", s, &n) != EOF)
{
s[LENGTH] = '\0';
tmp.first = s;
tmp.second = n;
::card.insert(tmp);
}
fclose(pf);
}
void v_personInit()
{
FILE* pf = fopen("person.txt", "r");
if (pf == nullptr)
{
perror("v_personInit fopen");
return;
}
Person tmp;
char name[MAX]; char id[MAX]; char pnumber[MAX]; char address[MAX]; char account[MAX]; double balance = 0.0;
while (fscanf(pf, "%s %s %s %s %s %lf", name, id, pnumber, address, account, &balance) != EOF)
{
name[MAX - 1] = '\0'; ::p_tmp._name = name;
id[MAX - 1] = '\0'; ::p_tmp._id = id;
pnumber[MAX - 1] = '\0'; ::p_tmp._pnumber = pnumber;
address[MAX - 1] = '\0'; ::p_tmp._address = address;
account[MAX - 1] = '\0'; ::p_tmp._account = account;
::p_tmp._balance = balance;
v_person.push_back(::p_tmp);
}
fclose(pf);
}
4. 保存数据并且排序
因为是用身份证号来读取银行卡号,所以当用户再次办理银行卡,就需要对v_bankcard进行排序;在查看之前需要排序,退出之前也需要排序。
//按照身份证号来排序
bool Compare1(Person p1, Person p2)
{
return p1._id < p2._id;
}
void Sort()
{
sort(v_person.begin(), v_person.end(), Compare1);
}
//保存数据
void cardSave()
{
FILE* pf = fopen("card.txt", "w");
if (pf == nullptr)
{
perror("DataCreate fopen");
return;
}
map<string, int>::iterator it = ::card.begin();
while (it != ::card.end())
{
fprintf(pf, "%s %d\n", (*it).first.c_str(), (*it).second);
++it;
}
fclose(pf);
}
void v_personSave()
{
FILE* pf = fopen("person.txt", "w");
if (pf == nullptr)
{
perror("DataCreate fopen");
return;
}
for (int i = 0; i < ::v_person.size(); ++i)
{
fprintf(pf, "%s %s %s %s %s %.2lf\n", v_person[i]._name.c_str(), v_person[i]._id.c_str(), v_person[i]._pnumber.c_str(), v_person[i]._address.c_str(), v_person[i]._account.c_str(), v_person[i]._balance);
}
fclose(pf);
}
void Save()
{
cardSave();
v_personSave();
}
上述函数搭配起来,再在主函数插入,就可以实现如下效果:
5. 查看所有人的银行卡信息
这个函数主要用来检验程序是否正确,数据是否输入正确,打印时,如果身份证号相同,则只打印一遍人的信息,代码如下:
void Show()
{
int i = 0;
while (i < v_person.size())
{
if ((i > 0) && (v_person[i]._id == v_person[i - 1]._id))
{
cout << v_person[i]._account << " " << v_person[i]._balance << endl;
}
else
{
cout << v_person[i]._name << " " << v_person[i]._id << " " << v_person[i]._pnumber << " " << v_person[i]._address << endl;
cout << v_person[i]._account << " " << v_person[i]._balance << endl;
}
++i;
}
}
效果如下:
6. 销户(注销银行卡)
销户有两种方法,一种是搜账号进行销毁,另一种是搜姓名进行销毁 (单姓名单卡号直接删,多姓名转换为按账号搜进行销毁) , 销户后将card中数据唤醒(即赋1),以便给其他用户使用。
- 按银行卡号删除
按银行卡号删除就进行遍历v_person,然后进行删除,删除之前需释放卡号(即将card.second = 1) - 按姓名删除
按姓名删除void DestoryN(int n)需要传姓名的个数,int FindN()返回姓名的个数 (注意这里是多对多),只有当n==1时,才能直接删,否则按银行卡删。
//通过银行卡号查找
vector<Person>::iterator FindA(const string& account)
{
vector<Person>::iterator it = v_person.begin();
while (it != v_person.end())
{
if ((*it)._account == account)
{
return it;
}
++it;
}
return it;
}
void Erase(vector<Person>::iterator& it)
{
map<string, int>::iterator itmap = card.begin();
//将card.second赋值为1
while (itmap != card.end())
{
if ((*itmap).first == (*it)._account)
{
(*itmap).second = 1;
break;
}
++itmap;
}
//删除
v_person.erase(it);
cout << "删除成功" << endl;
}
//通过姓名删除
void DestoryN(int n)
{
if (n == 1) //没有重名
{
cout << "请再次输入要删除账户的姓名>:";
string name;
cin >> name;
vector<Person>::iterator it = v_person.begin();
while (it != v_person.end())
{
if ((*it)._name == name)
{
Erase(it);
break;
}
++it;
}
}
else //有重名或一个人有多张卡
{
cout << "有相同的姓名或多张银行卡" << endl;
DestoryA();
}
}
//通过银行卡号删除
void DestoryA()
{
string account;
cout << "请输入要删除的账号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
Erase(it);
}
//查找姓名
int FindName()
{
int n = 0;
while (true)
{
cout << "请输入要查找的姓名>:";
string name;
int i = 0;
cin >> name;
while (i < v_person.size())
{
if (v_person[i]._name == name)
{
cout << v_person[i]._name << " " << v_person[i]._id << " " << v_person[i]._pnumber << " " << v_person[i]._address << " " << v_person[i]._account << " " << v_person[i]._balance << endl;
++n;
}
++i;
}
if (n == 0)
cout << "找不到,请重新输入!" << endl;
else
break;
}
return n;
}
//销户
void CloseAccount()
{
int n = 0;
int input = 0;
do
{
cout << "请选择搜索销户的方式>:0.退出销毁 1.姓名 2.银行卡号" << endl;
cout << "请选择>:";
cin >> input;
switch (input)
{
case 0:
break;
case 1:
n = FindName();
DestoryN(n);
break;
case 2:
DestoryA();
break;
default:
cout << "选择错误,请重新选择!" << endl;
break;
}
} while (input);
}
7. 存款、取款、转账
这些功能实现较简单,在v_person中遍历修改即可,代码如下:
//存款
void Deposit()
{
string account;
cout << "请输入要存款的银行卡号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
double balance = 0.0;
cout << "请输入要存款的金额>:";
cin >> balance;
(*it)._balance += balance;
cout << "存款成功" << endl;
}
//取款
void Withdrawal()
{
string account;
cout << "请输入要取的银行卡号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
double balance = 0.0;
cout << "请输入要取款的金额>:";
cin >> balance;
if ((*it)._balance < balance)
{
cout << "余额不足,取款失败! 余额为:" << (*it)._balance << endl;
}
else
{
(*it)._balance -= balance;
cout << "取款成功! 剩余余额为:" << (*it)._balance << endl;
}
}
//转账
void Transfer()
{
double d;
string a1;
string a2;
cout << "请输入被转的银行卡号:";
cin >> a1;
cout << "请输入转入的银行卡号:";
cin >> a2;
vector<Person>::iterator it1 = FindA(a1);
vector<Person>::iterator it2 = FindA(a2);
cout << "请输入要转的金额>:";
cin >> d;
if ((*it1)._balance < d)
{
cout << "余额不足,转账失败! 余额为:" << (*it1)._balance << endl;
}
else
{
(*it1)._balance -= d;
(*it2)._balance += d;
cout << "转账成功!两张卡的余额分别为:" << (*it1)._balance << " " << (*it2)._balance << endl;
}
}
4. 完整代码如下
银行管理系统大致思路如上,一些小细节就省略了。当然有些地方还需要一定的改善,比如可以加个办卡时间,还有好多地方需要二级菜单。
将上述一些代码放在Account类中,就可以跑起来
BAMSystem.h文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm> //sort
using namespace std;
#define CARD "1000000000" //默认银行卡号10位数
#define LENGTH 10
#define SIZE 1000 //默认写入1000个银行卡号
#define MAX 30
//人和卡的信息
class Person
{
public:
string _name; //姓名
string _id; //身份证号码
string _pnumber; //电话号码
string _address; //地址
string _account; //账号
double _balance = 0.0; //余额
};
Person p_tmp;
vector<Person> v_person;
//卡号是否使用
map<string, int> card;
//初始化
void cardInit()
{
FILE* pf = fopen("card.txt", "r");
if (pf == nullptr)
{
perror("DataInit fopen");
return;
}
pair<string, int> tmp;
char s[LENGTH + 1];
int n = 0;
while (fscanf(pf, "%s %d", s, &n) != EOF)
{
s[LENGTH] = '\0';
tmp.first = s;
tmp.second = n;
::card.insert(tmp);
}
fclose(pf);
}
void v_personInit()
{
FILE* pf = fopen("person.txt", "r");
if (pf == nullptr)
{
perror("v_personInit fopen");
return;
}
Person tmp;
char name[MAX]; char id[MAX]; char pnumber[MAX]; char address[MAX]; char account[MAX]; double balance = 0.0;
while (fscanf(pf, "%s %s %s %s %s %lf", name, id, pnumber, address, account, &balance) != EOF)
{
name[MAX - 1] = '\0'; ::p_tmp._name = name;
id[MAX - 1] = '\0'; ::p_tmp._id = id;
pnumber[MAX - 1] = '\0'; ::p_tmp._pnumber = pnumber;
address[MAX - 1] = '\0'; ::p_tmp._address = address;
account[MAX - 1] = '\0'; ::p_tmp._account = account;
::p_tmp._balance = balance;
v_person.push_back(::p_tmp);
}
fclose(pf);
}
//按照身份证号来排序
bool Compare1(Person p1, Person p2)
{
return p1._id < p2._id;
}
void Sort()
{
sort(v_person.begin(), v_person.end(), Compare1);
}
//保存数据
void cardSave()
{
FILE* pf = fopen("card.txt", "w");
if (pf == nullptr)
{
perror("DataCreate fopen");
return;
}
map<string, int>::iterator it = ::card.begin();
while (it != ::card.end())
{
fprintf(pf, "%s %d\n", (*it).first.c_str(), (*it).second);
++it;
}
fclose(pf);
}
void v_personSave()
{
FILE* pf = fopen("person.txt", "w");
if (pf == nullptr)
{
perror("DataCreate fopen");
return;
}
for (int i = 0; i < ::v_person.size(); ++i)
{
fprintf(pf, "%s %s %s %s %s %.2lf\n", v_person[i]._name.c_str(), v_person[i]._id.c_str(), v_person[i]._pnumber.c_str(), v_person[i]._address.c_str(), v_person[i]._account.c_str(), v_person[i]._balance);
}
fclose(pf);
}
void Save()
{
cardSave();
v_personSave();
}
//账户类
class Account :protected Person
{
public:
void OpenAccount()
{
//输入数据
cout << "请输入姓名>:";
cin >> _name;
cout << "请输入身份证号码>:";
cin >> _id;
cout << "请输入电话号码>:";
cin >> _pnumber;
cout << "请输入地址>:";
cin >> _address;
//初始化数据
::p_tmp._name = _name;
::p_tmp._id = _id;
::p_tmp._pnumber = _pnumber;
::p_tmp._address = _address;
::p_tmp._balance = 0;
//生成账号
int n = 1;
map<string, int>::iterator it = ::card.begin();
while (it != ::card.end())
{
if ((*it).second == 1)
{
n = 0;
::p_tmp._account = (*it).first;
(*it).second = 0; //使用后的卡号赋值为0
break;
}
++it;
}
if (n)
cout << "办理失败,请及时扩充银行卡号!" << endl;
else
{
v_person.push_back(::p_tmp);
cout << "办理成功,银行卡号为:" << ::p_tmp._account << endl;
}
}
//销户
void CloseAccount()
{
int n = 0;
int input = 0;
do
{
cout << "请选择搜索销户的方式>:0.退出销毁 1.姓名 2.银行卡号" << endl;
cout << "请选择>:";
cin >> input;
switch (input)
{
case 0:
break;
case 1:
n = FindName();
DestoryN(n);
break;
case 2:
DestoryA();
break;
default:
cout << "选择错误,请重新选择!" << endl;
break;
}
} while (input);
}
//存款
void Deposit()
{
string account;
cout << "请输入要存款的银行卡号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
double balance = 0.0;
cout << "请输入要存款的金额>:";
cin >> balance;
(*it)._balance += balance;
cout << "存款成功" << endl;
}
//取款
void Withdrawal()
{
string account;
cout << "请输入要取的银行卡号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
double balance = 0.0;
cout << "请输入要取款的金额>:";
cin >> balance;
if ((*it)._balance < balance)
{
cout << "余额不足,取款失败! 余额为:" << (*it)._balance << endl;
}
else
{
(*it)._balance -= balance;
cout << "取款成功! 剩余余额为:" << (*it)._balance << endl;
}
}
//转账
void Transfer()
{
double d;
string a1;
string a2;
cout << "请输入被转的银行卡号:";
cin >> a1;
cout << "请输入转入的银行卡号:";
cin >> a2;
vector<Person>::iterator it1 = FindA(a1);
vector<Person>::iterator it2 = FindA(a2);
cout << "请输入要转的金额>:";
cin >> d;
if ((*it1)._balance < d)
{
cout << "余额不足,转账失败! 余额为:" << (*it1)._balance << endl;
}
else
{
(*it1)._balance -= d;
(*it2)._balance += d;
cout << "转账成功!两张卡的余额分别为:" << (*it1)._balance << " " << (*it2)._balance << endl;
}
}
//查找姓名
int FindName()
{
int n = 0;
while (true)
{
cout << "请输入要查找的姓名>:";
string name;
int i = 0;
cin >> name;
while (i < v_person.size())
{
if (v_person[i]._name == name)
{
cout << v_person[i]._name << " " << v_person[i]._id << " " << v_person[i]._pnumber << " " << v_person[i]._address << " " << v_person[i]._account << " " << v_person[i]._balance << endl;
++n;
}
++i;
}
if (n == 0)
cout << "找不到,请重新输入!" << endl;
else
break;
}
return n;
}
//7.查看
void Show()
{
int i = 0;
while (i < v_person.size())
{
if ((i > 0) && (v_person[i]._id == v_person[i - 1]._id))
{
cout << v_person[i]._account << " " << v_person[i]._balance << endl;
}
else
{
cout << v_person[i]._name << " " << v_person[i]._id << " " << v_person[i]._pnumber << " " << v_person[i]._address << endl;
cout << v_person[i]._account << " " << v_person[i]._balance << endl;
}
++i;
}
}
private:
void Erase(vector<Person>::iterator& it)
{
map<string, int>::iterator itmap = card.begin();
//将card.second赋值为1
while (itmap != card.end())
{
if ((*itmap).first == (*it)._account)
{
(*itmap).second = 1;
break;
}
++itmap;
}
//删除
v_person.erase(it);
cout << "删除成功" << endl;
}
//通过姓名删除
void DestoryN(int n)
{
if (n == 1) //没有重名
{
cout << "请再次输入要删除账户的姓名>:";
string name;
cin >> name;
vector<Person>::iterator it = v_person.begin();
while (it != v_person.end())
{
if ((*it)._name == name)
{
Erase(it);
break;
}
++it;
}
}
else //有重名或一个人有多张卡
{
cout << "有相同的姓名或多张银行卡" << endl;
DestoryA();
}
}
//通过银行卡号删除
void DestoryA()
{
string account;
cout << "请输入要删除的账号>:";
cin >> account;
vector<Person>::iterator it = FindA(account);
Erase(it);
}
//通过银行卡号查找
vector<Person>::iterator FindA(const string& account)
{
vector<Person>::iterator it = v_person.begin();
while (it != v_person.end())
{
if ((*it)._account == account)
{
return it;
}
++it;
}
return it;
}
};
main.cpp文件
#include "BAMSystem.h"
void menu()
{
cout << "*******************************************" << endl;
cout << "******* 1.开户 2.销户 3.存款 **********" << endl;
cout << "******* 4.取款 5.转账 6.查询 **********" << endl;
cout << "******* 7.查看 8.刷新 0.退出 **********" << endl;
cout << "*******************************************" << endl;
}
int main()
{
cardInit();
v_personInit();
int input = 0;
Account a;
do
{
menu();
cout << "请选择>:";
cin >> input;
switch (input)
{
case 0:
Sort(); //先排序,在保存
Save();
cout << "退出程序" << endl;
break;
case 1:
a.OpenAccount();
break;
case 2:
a.CloseAccount();
break;
case 3:
a.Deposit();
break;
case 4:
a.Withdrawal();
break;
case 5:
a.Transfer();
break;
case 6:
a.FindName();
break;
case 7:
a.Show();
break;
case 8:
Sort(); //先排序,在保存
Save();
cout << "刷新成功" << endl;
break;
default:
cout << "选择错误,请重新选择。" << endl;
break;
}
} while (input);
return 0;
}
//只用来生成card.txt文件,生成card.txt文件后就不在使用,除非修改银行卡号的位数
//void DataCreate()
//{
// FILE* pf = fopen("card.txt", "w");
// if (pf == nullptr)
// {
// perror("DataCreate fopen");
// return;
// }
// map<string, int> m;
// string s = CARD;
// int n = SIZE;
// while (n--)
// {
// m.insert(pair<string, int>(s, 1));
// fprintf(pf, "%s %d\n", s.c_str(), 1);
// int tmp = stoi(s);
// ++tmp;
// s = to_string(tmp);
// }
// fclose(pf);
//}
下图为删除银行卡号效果: