C++入门编程实战(一)图书信息管理系统

开发语言:C++

开发环境:VS2017

程序说明:图书管理系统分为三个模块:添加新书、浏览全部、删除图书。

                三个文件分别是Book.h(包括Book类的声明)、Book.cpp(包括Book类中各方法的具体实现)、main.cpp(包括主函数及各模块的设计)

              

图书管理系统主界面如图

 

添加新书界面

浏览全部

Book.h代码如下

#pragma once
#define NUM1 128           //图书名称和Isbn编号最大长度
#define NUM2 50           //图书价格及作者最大长度
class CBook {
public:
	CBook(){}             //无参构造方法
	CBook(char* cName, char* cIsbn, char* cPrice, char* cAuthor);//有参构造方法
	~CBook(){}            //析构函数
public:
	char* GetName();//获取图书名称
	void SetName(char* cName);//设置图书名称
	char* GetIsbn();//获取图书ISBN编号
	void SetIsbn(char* cIsbn);//设置图书ISBN编号
	char* GetPrice();//获取图书价格
	void SetPrice(char* cPrice);//设置图书价格
	char* GetAuthor();//获取图书作者
	void SetAuthor(char* cAuthor);//设置图书作者
	void WriteData();             //写入数据
	void DeleteData(int iCount);  //删除数据
	void GetBookFromFile(int iCount);  //从文件中读取图书记录
protected:
	char m_cName[NUM1];
	char m_cIsbn[NUM1];
	char m_cPrice[NUM2];
	char m_cAuthor[NUM2];
}; 

Book.cpp代码如下

#include "Book.h"
#include <string.h>
#include <fstream>
#include <iostream>
#include <iomanip>
using namespace std;
CBook::CBook(char* cName, char* cIsbn, char* cPrice, char* cAuthor) {
	strncpy(m_cName, cName, NUM1);
	strncpy(m_cIsbn, cIsbn, NUM1);
	strncpy(m_cPrice, cPrice, NUM2);
	strncpy(m_cAuthor, cAuthor, NUM2);
}
char* CBook::GetName() {
	return m_cName;
}
void CBook::SetName(char* cName) {
	strncpy(m_cName, cName, NUM1);
}
char* CBook::GetIsbn() {
	return m_cIsbn;
}
void CBook::SetIsbn(char* cIsbn) {
	strncpy(m_cName, cIsbn, NUM1);
}
char* CBook::GetPrice() {
	return m_cPrice;
}
void CBook::SetPrice(char* cPrice) {
	strncpy(m_cPrice, cPrice, NUM2);
}
char* CBook::GetAuthor() {
	return m_cAuthor;
}
void CBook::SetAuthor(char* cAuthor) {
	strncpy(m_cAuthor, cAuthor, NUM2);
}
//函数WriteDate,GetBookFromFile,DeleteData是类对象对写文件的函数,相当于操作数据库的接口
void CBook::WriteData() {
	ofstream ofile;
	ofile.open("book.dat", ios::binary | ios::app);//以二进制格式(binary)打开book.dat, app:每次写操作前均定位到文件末尾
	try {
		ofile.write(m_cName, NUM1);//写入图书的信息
		ofile.write(m_cIsbn, NUM1);
		ofile.write(m_cPrice, NUM2);
		ofile.write(m_cAuthor, NUM2);
	}
	catch (...) {//catch(…)能够捕获多种数据类型的异常对象
		throw "file error occurred";
		ofile.close();
	}
	ofile.close();
}
//成员函数DeleteData负责将图书信息从文件中删除
void CBook::DeleteData(int iCount) {//删掉第iCount条记录
	long respos;
	int iDataCount = 0;
	/*头文件fstarem定义了3各类型来支持文件IO,ifstream从一个给定文件读取数据,
	ofatream向一个给定文件写入数据,以及fstream可以读写给定文件*/
	fstream file;
	fstream tmpfile;
	ofstream ofile;
	char cTempBuf[NUM1 + NUM1 + NUM2 + NUM2];
	file.open("book.dat", ios::binary | ios::in | ios::out);//二进制/读/写
	tmpfile.open("temp.dat", ios::binary | ios::out | ios::in | ios::trunc);
	/*seekg()是对输入文件定位,它有两个参数:第一个参数是偏移量,第二个参数是基地址。*/
	file.seekg(0, ios::end); //基地址为文件结束处,偏移地址为0,于是指针定位在文件结束处
	respos = file.tellg();//返回当前定位指针的位置,也代表着输入流的大小。
	iDataCount = respos / (NUM1 + NUM1 + NUM2 + NUM2);//总记录数=文件大小/基本量
	if (iCount<0 || iCount>iDataCount) {
		throw "Input number error";
	}
	else {//从第iCount+1条记录开始,将以后的记录先存至中间文件变量tmpfile,后将tmpfile的内容覆盖掉iCount条记录之后的内容,相当于删掉了第iCount条记录
		file.seekg((iCount)*(NUM1 + NUM1 + NUM2 + NUM2), ios::beg);//基地址为文件头,偏移量为基本量*iCount,即读写指针指向了第iCount条记录的起始位置
		for (int j = 0; j < (iDataCount - iCount); j++) {//将第iCount条记录后的记录先存入tmpfile
			memset(cTempBuf, 0, NUM1 + NUM1 + NUM2 + NUM2);//将cTempBuf清零
			file.read(cTempBuf, NUM1 + NUM1 + NUM2 + NUM2);//将file中的一条记录读入cTempBuf
			tmpfile.write(cTempBuf, NUM1 + NUM1 + NUM2 + NUM2);//将cTempBuf中的一条记录写入tmpfile
		}
		file.close();
		tmpfile.seekg(0, ios::beg);//将指针定位在文件头
		ofile.open("book.dat");
		ofile.seekp((iCount - 1)*(NUM1 + NUM1 + NUM2 + NUM2), ios::beg);//将指针定位到第iCount-1条记录的结束位置
		for (int i = 0; i < (iDataCount - iCount); i++) {
			memset(cTempBuf, 0, NUM1 + NUM1 + NUM2 + NUM2);
			tmpfile.read(cTempBuf, NUM1 + NUM1 + NUM2 + NUM2);
			ofile.write(cTempBuf, NUM1 + NUM1 + NUM2 + NUM2);//将cTempBuf中的一条记录写入ofile
		}
	}
	tmpfile.close();
	ofile.close();
	remove("temp.dat");
}
//成员函数GetBookFromFile从文件中读取数据来构建对象
void CBook::GetBookFromFile(int iCount) {
	char cName[NUM1];
	char cIsbn[NUM1];
	char cPrice[NUM2];
	char cAuthor[NUM2];
	ifstream ifile;
	ifile.open("book.dat", ios::binary);
	try {
		ifile.seekg(iCount*(NUM1 + NUM1 + NUM2 + NUM2), ios::beg);
		ifile.read(cName, NUM1);
		if (ifile.tellg() > 0)
			strncpy(m_cName, cName, NUM1);
		ifile.read(cIsbn, NUM1);
		if (ifile.tellg() > 0)
			strncpy(m_cIsbn, cIsbn, NUM1);
		ifile.read(cPrice, NUM2);
		if (ifile.tellg() > 0)
			strncpy(m_cPrice, cPrice, NUM2);
		ifile.read(cAuthor, NUM2);
		if (ifile.tellg() > 0)
			strncpy(m_cAuthor, cAuthor, NUM2);
	}
	catch (...) {
		throw "file error occured";
		ifile.close();
	}
	ifile.close();
}

main.cpp代码如下

#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <fstream>
#include "Book.h"

#define CMD_COLS 80
#define CMD_LINES 25
using namespace std;

void SetScreenGrid();//设置屏幕显示的行数和列数
void ClearScreen();//清除屏幕信息
void SetSysCaption(const char *pText);//设置窗体标题栏
void ShowWelcome();//显示欢迎信息
void ShowRootMenu();//显示开始菜单
void WaitView(int iCurPage);//浏览数据时等待用户操作
void WaitUser();//等待用户操作
void GuideInput();//使用向导添加图书信息
int GetSelect();//获得用户菜单选择
long GetFileLength(ifstream &ifs);//获取文件长度
void ViewData(int iSelPage);//浏览所有图书记录
void DeleteBookFromFile();//在文件中产生图书信息
void mainloop();//主循环
void main()
{

	SetScreenGrid();
	SetSysCaption("图书管理系统");
	mainloop();
}

void SetScreenGrid() {
	char sysSetBuf[80];
	sprintf(sysSetBuf, "mode con cols=%d lines=%d", CMD_COLS, CMD_LINES);
	system(sysSetBuf);
}
void SetSysCaption()
{
	system("title Sample");
}
void SetSysCaption(const char *pText)
{
	char sysSetBuf[80];
	sprintf(sysSetBuf, "title %s", pText);
	system(sysSetBuf);
}

void ClearScreen() {
	system("cls");
}

void ShowWelcome() {
	for (int i = 0; i < 7; i++) {
		cout << endl;
	}
	cout << setw(40);
	cout << "******************" << endl;
	cout << setw(40);
	cout << "***图书管理系统***" << endl;
	cout << setw(40);
	cout << "******************" << endl;
}

void ShowRootMenu() {
	cout << setw(35);
	cout << "请选择功能" << endl;
	cout << endl;
	cout << setw(35);
	cout << "1 添加新书" << endl;
	cout << endl;
	cout << setw(35);
	cout << "2 浏览全部" << endl;
	cout << endl;
	cout << setw(35);
	cout << "3 删除图书" << endl;
	cout << endl;
}

void WaitUser() {
	int iInputPage = 0;
	cout << "enter 返回主菜单 q退出" << endl;
	char buf[256];
	gets_s(buf);
	if (buf[0] == 'q')
		system("exit");
}

void mainloop(){
	ShowWelcome();
	while (1) {
		ClearScreen();
		ShowWelcome();
		ShowRootMenu();
		switch (GetSelect()) {
		case 1:
			ClearScreen();
			GuideInput();
			break;
		case 2:
			ClearScreen();
			ViewData(1);
			break;
		case 3:
			ClearScreen();
			DeleteBookFromFile();
			break;
		}
	}
}

int GetSelect() {
	char buf[256];
	gets_s(buf);
	return atoi(buf);
}

void GuideInput() {
	char inName[NUM1];
	char inIsbn[NUM1];
	char inPrice[NUM2];
	char inAuthor[NUM2];

	cout << "输入书名" << endl;
	cin >> inName;
	cout << "输入Isbn" << endl;
	cin >> inIsbn;
	cout << "输入价格" << endl;
	cin >> inPrice;
	cout << "输入作者" << endl;
	cin >> inAuthor;
	CBook book(inName, inIsbn, inPrice, inAuthor);
	book.WriteData();
	cout << "Write Finish" << endl;
	WaitUser();
}
void ViewData(int iSelPage=1)//浏览图书
{
	int iPage = 0;//总页数
	int iCurPage = 0;//当前页数
	int iDataCount = 0;//总书数
	char inName[NUM1];
	char inIsbn[NUM1];
	char inPrice[NUM2];
	char inAuthor[NUM2];
	bool bIndex = false;
	int iFileLength;
	iCurPage = iSelPage;
	ifstream ifile;
	ifile.open("book.dat", ios::binary);
	iFileLength = GetFileLength(ifile);
	iDataCount = iFileLength / (NUM1 + NUM1 + NUM2 + NUM2);//根据文件长度,计算文件中总记录数
	if (iDataCount >= 1)
		bIndex = true;
	iPage = iDataCount / 20 + 1;
	ClearScreen();//清除屏幕信息
	cout << "共有记录" << iDataCount << " ";
	cout << "共有页数" << iPage << " ";
	cout << "当前页数" << iCurPage << " ";
	cout << "n 显示下一页 m 返回" <<endl;
	cout << setw(3) << "Index";
	cout << setw(20) << "Name"<<setw(24)<<"Isbn";
	cout << setw(15) << "Price" << setw(13) << "Author";
	cout << endl;
	try {
		//根据图书记录编号查找在文件中的位置
		ifile.seekg((iCurPage - 1) * 20 * (NUM1 + NUM1 + NUM2 + NUM2), ios::beg);//偏移量=页数*基本量,从文件头开始
		if (!ifile.fail()) {
			for (int i = 1; i < 21; i++) {
				memset(inName, 0, 128);//清零
				memset(inIsbn, 0, 128);
				memset(inPrice, 0, 50);
				memset(inAuthor, 0, 50);
				if (bIndex) {//找到了书
					cout << setw(3) << ((iCurPage - 1) * 20 + i);//多输出了一个索引
					ifile.read(inName, NUM1);
					cout << setw(24) << inName;
					ifile.read(inIsbn, NUM1);
					cout << setw(24) << inIsbn;
					ifile.read(inPrice, NUM2);
					cout << setw(12) << inPrice;//闪退原因是将这里的12误写成了24.。。。。。。
					ifile.read(inAuthor, NUM2);
					cout << setw(12) << inAuthor;
					cout << endl;
				}
				if (ifile.tellg() < 0)
					bIndex = false;
				else
					bIndex = true;
			}
		}
	}
	catch (...) {
		cout << "throw file exception" << endl;
		throw "file error occurred";//抛出异常
		ifile.close();
	}
	if (iCurPage < iPage) {
		iCurPage = iCurPage + 1;
		WaitView(iCurPage);//等待用户处理
	}
	else {
		WaitView(iCurPage);
	}
	ifile.close();
}
long GetFileLength(ifstream &ifs) {
	long temppos;
	long respos;
	temppos = ifs.tellg();
	ifs.seekg(0, ios::end);
	respos = ifs.tellg();
	ifs.seekg(temppos, ios::beg);
	return respos;
}
void DeleteBookFromFile() {//
	int iDelCount;
	cout << "Input delete index" << endl;
	cin >> iDelCount;
	CBook tmpbook;
	tmpbook.DeleteData(iDelCount);
	cout << "Delete Finish" << endl;
	WaitUser();
}
void WaitView(int iCurPage)
{
	char buf[256];
	gets_s(buf);
	if (buf[0] == 'q')
		system("exit");
	if (buf[0] == 'm')
		mainloop();
	if (buf[0] == 'n')
		ViewData(iCurPage);
}



图书馆流通管理软件 作为面向对象程序设计的第步,在实际系统中,识别对象和类是很重要的。在这里,我们以图书馆流通管理系统为例,介绍识别对象与类的般方法。 1、对象和类的识别 在一个信息系统内识别对象最简单也是最主要的方法是对具体事物的属性和功能进行分析,旦识别到一个对象,就能识别出相同类型的所有对象,把它们归纳为类。 图书馆流通系统内,有书、读者、借书证、管理人员、借书还书行为等对象和事件,他们分别各是一个群体。例如每个图书馆都有几万甚至几十万册图书,每册图书都是一个对象,它们形成图书类(在此暂时用Item款目表示)。相应的,在图书流通系统内,还可以得到以下类: 读者(Reader)类,在图书馆注册的每位借书人都是一个读者类的对象; 图书借阅信息类(Loan),每次发生借书行为,都产生一个借阅信息的对象; 管理人员类(Manager),是借书还书行为的操作人。 借书证对象虽然是实实在在的对象,但每位读者对应本借书证,且只需要知道其编号,因此不需要另外定义类,只作为读者类的一个数据成员。 同一个信息系统,从不同的角度分析,或根据要求的不同,有不同的侧重面,这样建立的对象模型不同,可能得出的分类方法也不同。 2、对象属性的识别 每个对象的情况称为对象的属性,同类型的对象具有共同的属性,只是每个对象的属性值不定相同。属性是对一个对象状态的描述,如“在馆图书类”,从流通管理的角度来看,应包含书名Title、作者名Author、分类号IndexCode、册数Number、条码号BarCode等属性。 其它类的属性如下: 读者类,包含姓名Name、职务Position、年龄Age、借书证编号Code等。一个读者允许借阅若干册书,在此用一个Item的数组items保存相应信息。另外对读者所借书册数要统计,定义一个计数的成员Counter; 图书借阅信息类,包含所借书item、借书人reader、借书操作员manager等; 管理人员类,包含姓名Name、年龄Age、工号Code等; 管理人员类只有在发生借书行为时才作为操作人员记录下来,可以作为借书信息类的一个数据成员记录备查,程序中未定义其对象。 同一个类(对象),从不同的角度分析,或根据要求的不同,描述它的属性也可能不致。 3、对象功能的确定 对象的功能指为了达到目的必须执行的动作,或是对象对所发生事件的反应。功能也可称为对象的操作。 在图书馆流通管理系统内,图书类应包含为各属性赋值(Set…)的操作、读取条码(GetCode)和显示图书基本信息(Show)的操作,另外还定义了缺省构造函数和拷贝构造函数。 读者类,需定义为各属性赋值(Set…)的操作、读取借书证号的操作,借书和还书需要向所借书数组中添加或减少书,定义AddBook和DelBook两个操作,还有显示所借书的操作ShowBooks。 4、对象和类的标记 在这里采用科德(Coad)定义的面向对象方法的描述符号,这方法是Peter Coad和Ed YourDon于1990年提出的,这方法的优点是图形简单、易于理解和掌握,但对类和对象属性的访问权限无法进行有效的描述。 科德标记法中,使用一个圆角矩形表示类,矩形内部分为三个部分,上部写类名,中部写属性(数据成员),下部表示该类的操作(函数成员)。对象是类的实例,在科德标记法中,在相应类标记外加一个圆角矩形框表示对象,并将矩形内部的表示类名的地方写上对象名,如图4.15。 科德表示法可形象地用扑克牌示意图来表示。如图4.16,一个类可能有0个或1个2个3个甚至更多对象,但没有实例化以前,它们在图上只画一个圆角矩形,就像叠扑克牌,只看见最上面的张牌;当把这叠牌散开时,它们是若干个对象,就像类被实例化了。 科德标记法还有表示连接的符号,如图4.17,一个带线段的半圆弧表示A是通用类,B是特殊类,中间带空心三角形的线段表示A类包含B类即整体与部分的关系,中间带实心箭头的线段表示A向B发送消息,段实线表示对象之间的连接线。 根据上面对的图书馆流通管理系统的分析,在图4.18中,用科德标记法表示Item, Reader, Manager, Loan四个类,它们的数据成员及其类型、函数成员的原型都在图中标出,但无法标出它们的访问权限。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值