首页 > 其他分享 >抽象类和文件读写

抽象类和文件读写

时间:2022-08-30 21:46:06浏览次数:58  
标签:文件 int double 读写 shapes break 抽象类 unitPrice ptr

UML类图

代码

#include <iostream>
#include <cmath>
#include <fstream>
#include <sstream>
#include <string>
#include <stdexcept>
#include <exception>
#include <iomanip>
#include <cassert>
#include "Array.h"
using namespace std;
const double PI = 3.14;
void showMenu();
//抽象类框架类
class Shape {
public:
	Shape(int classId, double unitPrice) :classId(classId), unitPrice(unitPrice) {}
	virtual void setInfo() = 0; // 纯虚函数,设置框架的参数
	virtual void getInfo() = 0; // 纯虚函数,得到框架的参数
	virtual double getCircumference() = 0; // 纯虚函数,得到框架的周长
	bool operator > (Shape& shape2); // 对大于(>)运算符进行重载,用于比较框架的周长
	virtual void showInfo() = 0;
	int getClassId() {
		return this->classId;
	}
	void setUnitPrice(double unitPrice) {
		this->unitPrice = unitPrice;
	}
	double getUnitPrice() {
		return this->unitPrice;
	}
	virtual ~Shape() {}
private:
	int classId;
	double unitPrice;
};
bool Shape::operator > (Shape& shape2) {
	if (this->getCircumference() > shape2.getCircumference()) {
		return true;
	} else {
		return false;
	}
}

// 圆
class Circle :public Shape {
public:
	Circle(double unitPrice = 0, int classId = 1) :Shape(classId, unitPrice), radius(0) {}
	Circle(double radius, double unitPrice, int classId = 1) :
		Shape(classId, unitPrice), radius(radius) {
	}
	void setInfo(); // 覆盖基类虚函数,设置圆的参数(半径)
	void getInfo(); // 覆盖基类虚函数,打印圆的参数(半径,周长)
	void showInfo();
	double getCircumference(); // 覆盖基类虚函数,计算框架的周长
	~Circle() {}
private:
	double radius; // 半径
};

double Circle::getCircumference() {
	double circumference = PI * radius * radius;
	return circumference;
}
void Circle::setInfo() {
	double r;
	cout << "请输入圆的半径:";
	cin >> r;
	while (true) {
		if (r > 0) {
			this->radius = r;
			break;
		} else {
			cout << "请输入大于0的数!" << endl;
		}
	}
}
void Circle::getInfo() {
	cout << "圆,半径" << fixed << setprecision(2) << this->radius << ",周长"
		<< fixed << setprecision(2) << this->getCircumference() << endl;
}
void Circle::showInfo() {
	cout << "圆:" << getClassId() << " 半径" << radius << " 单价" << getUnitPrice() << endl;
}

// 长方形
class Rectangle :public Shape {
public:
	Rectangle(double unitPrice = 0, int classId = 2) :Shape(classId, unitPrice), length(0), width(0) {}
	Rectangle(double length, double width, double unitPrice, int classId = 2) :
		Shape(classId, unitPrice), length(length), width(width) {
	}
	void setInfo(); // 覆盖基类虚函数,设置长方形的参数(长,宽)
	void getInfo(); // 覆盖基类虚函数,打印长方形的参数(长,宽,周长)
	void showInfo();
	double getCircumference(); // 覆盖基类虚函数,计算框架的周长
	~Rectangle() {}
private:
	double length; // 长
	double width; // 宽
};

double Rectangle::getCircumference() {
	double circumference = 2 * (length + width);
	return circumference;
}
void Rectangle::setInfo() {
	double x1, x2;
	cout << "请输入长方形的长和宽:";
	cin >> x1 >> x2;
	while (true) {
		if (x1 > 0 && x2 > 0) {
			if (x1 > x2) {
				this->length = x1;
				this->width = x2;
			} else {
				this->length = x2;
				this->width = x1;
			}
			break;
		} else {
			cout << "请输入大于0的数!" << endl;
		}
	}
}
void Rectangle::getInfo() {
	cout << "长方形,长" << fixed << setprecision(2) << this->length
		<< ",宽" << fixed << setprecision(2) << this->width<< ",周长" 
		<< fixed << setprecision(2) << this->getCircumference() << endl;
}
void Rectangle::showInfo() {
	cout << "长方形:" << getClassId() << " 长" << length 
		<< " 宽" << width << " 单价" << getUnitPrice() << endl;
}

// 直角三角形
class RightTriangle :public Shape {
public:
	RightTriangle(double unitPrice = 0, int classId = 3) :Shape(classId, unitPrice), side1(0), side2(0) {}
	RightTriangle(double side1, double side2, double unitPrice, int classId = 3) :
		Shape(classId, unitPrice), side1(side1), side2(side2) {
	};
	void setInfo(); // 覆盖基类虚函数,设置直角三角形的参数(两条直角边)
	void getInfo(); // 覆盖基类虚函数,设置直角三角形的参数(两条直角边,周长)
	void showInfo();
	double getCircumference(); // 覆盖基类虚函数,计算框架的周长
	~RightTriangle() {}
private:
	double side1; // 直角边1
	double side2; // 直角边2
};

double RightTriangle::getCircumference() {
	double hypotenuse = sqrt((side1 * side1) + (side2 * side2));
	double circumference = hypotenuse + side1 + side2;
	return circumference;
}
void RightTriangle::setInfo() {
	double x1,x2;
	cout << "请输入直角三角形的两条直角边:";
	cin >> x1 >> x2;
	while (true) {
		if (x1 > 0 && x2 > 0) {
			this->side1 = x1;
			this->side2 = x2;
			break;
		} else {
			cout << "请输入大于0的数!" << endl;
		}
	}
}
void RightTriangle::getInfo() {
	cout << "直角三角形,直角边" << fixed << setprecision(2) << this->side1
		<< ",直角边" << fixed << setprecision(2) << this->side2 << ",周长"
		<< fixed << setprecision(2) << this->getCircumference() << endl;
}
void RightTriangle::showInfo() {
	cout << "直角三角形:" << getClassId() << ". 直角边" << side1 
		<< " 直角边" << side2 << " 单价" << getUnitPrice() << endl;
}

class Square :public Rectangle {
public:
	Square(double unitPrice = 0, int classId = 4) :Rectangle(unitPrice,classId), side(0) {}
	Square(double side, double unitPrice = 0, int classId = 4) :
		Rectangle(side, side, unitPrice, classId), side(side) {
	}
	void setInfo();
	void getInfo();
	void showInfo();
	double getCircumference();
	~Square() {}
private:
	double side; // 边长
};
void Square::setInfo() {
	double x;
	cout << "请输入正方形的边长:";
	cin >> x;
	while (true) {
		if (x > 0) {
			this->side = x;
			break;
		} else {
			cout << "请输入大于0的数!" << endl;
		}
	}
}
void Square::getInfo() {
	cout << "正方形,边长" << fixed << setprecision(2) << this->side << ",周长"
		<< fixed << setprecision(2) << this->getCircumference() << endl;
}
double Square::getCircumference() {
	double circumference = 4 * side;
	return circumference;
}
void Square::showInfo() {
	cout << "正方形:" << getClassId() << ". 边长" << side << " 单价" << getUnitPrice() << endl;
}

//设计一个函数,生成框架产品的目录清单。用户可以重复选择多种框架图案,并给出其大小参数,直至输入-1后,选择产品结束。
void showMenu() {
	cout << "******************************************" << endl;
	cout << "  1. Circle(圆)                " << endl;
	cout << "  2. Rectangle(长方形)          " << endl;
	cout << "  3. RightTriangle(直角三角形)  " << endl;
	cout << "******************************************" << endl;
	cout << "Please select the shape (enter -1 to quit): " << endl;
}

//将新创建Shape对象插入有序动态数组中
void insertSort(Array<Shape*>& shapes, int number, Shape* ptr) {
	int flag = 0;
	for (int i = 0; i < number; i++) {
		if (*shapes[i] > *ptr) {
			flag = i;
			break;
		}
	}
	for (int i = number; i > flag; i--) {
		shapes[i] = shapes[i - 1];
	}
	shapes[flag] = ptr;
}

//自定义异常类 FileNotOpenedException,公有继承 exception 类。
class FileNotOpenedException:public exception{
public:
	FileNotOpenedException(const string& what_arg) :what_arg(what_arg) {}
	const char* what()const { return what_arg.c_str(); }
	~FileNotOpenedException() {}
private:
	string what_arg;
};

//根据文本文件的内容,生成框架产品的目录清单,将清单中的产品读取到动态数组中,然后排序并输出到显示器上。
int createShapes(const char* filename, Array<Shape*>& shapes) {
	int shapeNum = 0;//框架数目
	int classId;//框架classId
	int size = shapes.getSize();//得到动态数组的大小
	const double value = 3.0;//所有框架的几何参数都默认为3厘米
	string line;//读取一行
	string shapeName;//框架名称
	double unitPrice;//框架单价

	cout << "从文件" << filename << "中读取数据,生成框架产品的目录清单" << endl;
	ifstream fileStream(filename);

	/*当读取文本文件 Shapes.txt 时,如果没有正确打开该文件,就抛出此异常对象。
	并在程序中适当的位置处理异常,给出错误提示。*/
	if (!fileStream) {
		ostringstream message;
		message << "Cannot open " << filename << endl;
		throw FileNotOpenedException(message.str());
	}

	//正确打开 Shapes.txt 时,按行读取文件数据
	while (getline(fileStream, line)) {
		istringstream strStream(line);//创建字符串输入流对象
		Shape* ptr = nullptr;//指针置空
		strStream >> classId;
		string str1, str2;
		strStream >> str1 >> str2 >> unitPrice;
		// 每行的样式:
		// 1. Circle, 4.0
		// 语句执行之后,str1的值是".", str2的值是"Circle,", unitPrice的值是4.0
		switch (classId) {
		case 1:
			ptr = new Circle(value, unitPrice);
			break;
		case 2:
			ptr = new Rectangle(value, value, unitPrice);
			break;
		case 3:
			ptr = new RightTriangle(value, value, unitPrice);
			break;
		case 4:
			ptr = new Square(value, unitPrice);
			break;
		default:
			cout << "不支持的classId,请检查文件内容" << endl;
			break;
		}
		//将清单中的产品读取到动态数组中并排序
		insertSort(shapes, shapeNum, ptr);
		shapeNum++;
		if (shapeNum >= size) {
			size *= 2;
			shapes.resize(size);
		}
	}

	//将清单中的产品输出到显示器上
	for (int i = 0; i < shapeNum; i++) {
		shapes[i]->showInfo();
	}
	return shapeNum;
}

//将文本文件中的产品,按其分类,分别存入相应的二进制固定长文件。
void writeBinaryFiles(Array<Shape*>& shapes, int shapeNum) {
	cout << endl << "将文本文件中的产品,按其分类,分别存入相应的二进制固定长文件" << endl;

	ofstream circleFile("Circle.dat", ios_base::out | ios_base::binary);
	ofstream rectangleFile("Rectangle.dat", ios_base::out | ios_base::binary);
	ofstream rightriangleFile("Rightriangle.dat", ios_base::out | ios_base::binary);
	ofstream squareFile("Square.dat", ios_base::out | ios_base::binary);

	for (int i = 0; i < shapeNum; i++) {
		int classId = shapes[i]->getClassId();
		switch (classId) {
		case 1: {
			Circle* ptr = dynamic_cast<Circle*>(shapes[i]);
			circleFile.write(reinterpret_cast<char*>(ptr), sizeof(*ptr));
			break;
		}
		case 2: {
			Rectangle* ptr = dynamic_cast<Rectangle*>(shapes[i]);
			rectangleFile.write(reinterpret_cast<char*>(ptr), sizeof(*ptr));
			break;
		}
		case 3: {
			RightTriangle* ptr = dynamic_cast<RightTriangle*>(shapes[i]);
			rightriangleFile.write(reinterpret_cast<char*>(ptr), sizeof(*ptr));
			break;
		}
		case 4: {
			Square* ptr = dynamic_cast<Square*>(shapes[i]);
			squareFile.write(reinterpret_cast<char*>(ptr), sizeof(*ptr));
			break;
		}
		}
	}
	//文件写入操作完成后要记得关闭文件,否则会占用资源
	circleFile.close();
	rectangleFile.close();
	rightriangleFile.close();
	squareFile.close();
	cout << "文件写入操作完成" << endl;
}

//将产品从二进制文件中读取出来,按照类别输出到显示器上。
void readBinaryFiles() {
	cout << endl << "从二进制文件中读取数据" << endl;

	ifstream circleFile("Circle.dat", ios_base::in | ios_base::binary);
	ifstream rectangleFile("Rectangle.dat", ios_base::in | ios_base::binary);
	ifstream rightriangleFile("Rightriangle.dat", ios_base::in | ios_base::binary);
	ifstream squareFile("Square.dat", ios_base::in | ios_base::binary);

	Circle circle;
	while (circleFile.read(reinterpret_cast<char*>(&circle), sizeof(circle))) {
		circle.showInfo();
	}
	circleFile.close();

	Rectangle rectangle;
	while (rectangleFile.read(reinterpret_cast<char*>(&rectangle), sizeof(rectangle))) {
		rectangle.showInfo();
	}
	rectangleFile.close();

	RightTriangle rightriangle;
	while (rightriangleFile.read(reinterpret_cast<char*>(&rightriangle), sizeof(rightriangle))) {
		rightriangle.showInfo();
	}
	rightriangleFile.close();

	Square square;
	while (squareFile.read(reinterpret_cast<char*>(&square), sizeof(square))) {
		square.showInfo();
	}
	squareFile.close();
	//文件读取操作完成后要记得关闭文件,否则会占用资源
	cout << "文件读取操作完成" << endl;
}

int main() {
	//Array<Shape*>shapes(2); // 使用动态数组存放抽象类Shape指针
	//int count = 0;
	//int choice;
	//// 显示菜单
	//showMenu();
	//cin >> choice;
	//while (choice != -1) {
	//	if (count == shapes.getSize()) {
	//		shapes.resize(count * 2);
	//	}
	//	switch (choice) {
	//	case 1:
	//		shapes[count] = new Circle;
	//		shapes[count]->setInfo();
	//		count++;
	//		break;
	//	case 2:
	//		shapes[count] = new Rectangle;
	//		shapes[count]->setInfo();
	//		count++;
	//		break;
	//	case 3:
	//		shapes[count] = new RightTriangle;
	//		shapes[count]->setInfo();
	//		count++;
	//		break;
	//	default:
	//		cout << "Not supported! Please select again!\n";
	//		break;
	//	}	
	//	showMenu();
	//	cin >> choice;
	//}
	// 使用插入排序算法,将所选的多种产品按周长从大到小进行排序。
	//for (int i = 1; i < count; i++) {
	//	int j = i;
	//	Shape* temp = nullptr;
	//	temp = shapes[i];
	//	while ((j > 0) && (*temp > *shapes[j - 1])) {
	//		shapes[j] = shapes[j - 1];
	//		j--;
	//	}
	//	shapes[j] = temp;
	//}
	//for (int i = 0; i < count; i++) {
	//	cout << i + 1 << ". ";
	//	shapes[i]->getInfo();
	//}
	//for (int i = 0; i < count; i++) {
	//	delete shapes[i];
	//}
	Array<Shape*> shapes(2);// 使用动态数组存放抽象类Shape指针
	for (int i = 0; i < 2; i++) {
		shapes[i] = nullptr;
	}

	int shapeNum = 0;
	try {
		shapeNum = createShapes("Shapes.txt", shapes);
	} catch (FileNotOpenedException& e) {
		cout << "Caught an exception: " << e.what() << endl;
	}

	writeBinaryFiles(shapes, shapeNum);
	readBinaryFiles();

	return 0;
}

标签:文件,int,double,读写,shapes,break,抽象类,unitPrice,ptr
From: https://www.cnblogs.com/catting123/p/16640935.html

相关文章