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