// Assignment 4 Solution - Winter 2021 #include #include #include #include #include #include #include #include // for sqrt() using namespace std; const double PI = 3.14159265359; double get_doubleFromBinaryFile(ifstream& fin); class Thing { public: string name() const; virtual ~Thing() = 0; }; class GeometricSolid : virtual public Thing { public: GeometricSolid() = default; ~GeometricSolid() = default; virtual double volume() const = 0; }; class ColoredThing : virtual public Thing { public: ColoredThing(double weight, string color); string color() const; virtual double density() const = 0; protected: string color_; double weight_; }; class RectangularPrism : public GeometricSolid { protected: double length_; double width_; double height_; public: RectangularPrism(double length = 0, double width = 0, double height = 0); double volume() const; }; class Cube : public RectangularPrism { public: Cube(double s = 0); }; class Circular : public GeometricSolid { public: Circular(double radius = 0); double radius() const; protected: double radius_; }; class Sphere : public Circular { public: Sphere(double radius = 0); double volume() const; }; class Cylinder : public Circular { protected: double height_; public: Cylinder(double radius = 0, double height = 0); double volume() const; }; class ColoredCylinder : public Cylinder, public ColoredThing { public: ColoredCylinder(double radius, double height, double weight, string color); double density() const; }; class ColoredSphere : public Sphere, public ColoredThing { public: ColoredSphere(double radius, double weight, string color); double density() const; }; class ColoredRectangularPrism : public RectangularPrism, public ColoredThing { public: ColoredRectangularPrism(double length, double width, double height, double weight, string color); double density() const; }; class ColoredCube : public Cube, public ColoredThing { public: ColoredCube(double side, double weight, string color); double density() const; }; enum SolidType { CylinderType = 1, SphereType = 2, RectangularPrismType = 4, CubeType = 8}; enum Color { None = 0, Red = 1, Blue = 2, Green = 4, Yellow = 8}; const string ColorStr[] = {"","Red","Blue","","Green","","","","Yellow"}; ostream& operator<<(ostream& out, const GeometricSolid& S); ostream& operator<<(ostream& out, const ColoredThing& CT); ostream& operator<<(ostream& out, const Thing& object); int main() { unsigned char code; SolidType solidType; Color color; const string inputFile("c:/temp/ass4data.bin"); ifstream fin(inputFile,ios_base::binary); if (!fin) { cerr << "Cannot open input file " << inputFile << endl; exit(1); } Thing* ptrThing; ofstream fout("c:/temp/ass4data.txt"); cout << fixed << setprecision(4); double d1, d2, d3, d4; cout << left << setw(24) << "Type of Object" << right << setw(12) << "Volume" << ' ' << left << setw(8) << "Color" << right << setw(12) << "Density" << endl; fout << "1st Byte Toggled -Nibbles- -------- Doubles ----------" << endl; for (unsigned i = 0; i < 50; ++i) { fin.read(reinterpret_cast(&code), sizeof (code)); fout << setw(8) << dec << static_cast(code); code ^= 0x81; fout << hex << showbase << setw(8) << static_cast(code); solidType = static_cast(code >> 4); fout << setw(6) << static_cast(solidType); color = static_cast(code & 0x0f); fout << setw(6) << static_cast(color); fout << setprecision(5) << fixed; switch (solidType) { case CylinderType: d1 = get_doubleFromBinaryFile(fin); d2 = get_doubleFromBinaryFile(fin); fout << setw(10) << d1 << setw(10) << d2; if(color) { d3 = get_doubleFromBinaryFile(fin); fout << setw(10) << d3; ptrThing = new ColoredCylinder(d1, d2, d3, ColorStr[color]); } else ptrThing = new Cylinder(d1, d2); break; case SphereType: d1 = get_doubleFromBinaryFile(fin); fout << setw(10) << d1; if(color) { d2 = get_doubleFromBinaryFile(fin); fout << setw(10) << d2; ptrThing = new ColoredSphere(d1, d2, ColorStr[color]); } else ptrThing = new Sphere(d1); break; case RectangularPrismType: d1 = get_doubleFromBinaryFile(fin); d2 = get_doubleFromBinaryFile(fin); d3 = get_doubleFromBinaryFile(fin); fout << setw(10) << d1 << setw(10) << d2 << setw(10) << d3; if(color) { d4 = get_doubleFromBinaryFile(fin); fout << setw(10) << d4; ptrThing = new ColoredRectangularPrism(d1, d2, d3, d4, ColorStr[color]); } else ptrThing = new RectangularPrism(d1, d2, d3); break; case CubeType: d1 = get_doubleFromBinaryFile(fin); fout << setw(10) << d1; if(color) { d2 = get_doubleFromBinaryFile(fin); fout << setw(10) << d2; ptrThing = new ColoredCube(d1, d2, ColorStr[color]); } else ptrThing = new Cube(d1); break; default: cerr << "*** Error: unable to process SolidType = " << static_cast(solidType) << endl; exit(5); } // The following output was merged into: cout << *ptrThing << endl; /* if (dynamic_cast (ptrThing)) { cout << (*(dynamic_cast (ptrThing))); } if (dynamic_cast (ptrThing)) { cout << (*(dynamic_cast (ptrThing))); } cout << endl; */ cout << *ptrThing << endl; fout << endl; delete ptrThing; } fin.close(); return 0; } double get_doubleFromBinaryFile(ifstream & fin) { double d; fin.read(reinterpret_cast (&d), sizeof (d)); return d; } ////////// Thing class member functions ////////// Thing::~Thing() { } string Thing::name() const { string classname = typeid(*this).name(); #ifdef _MSC_VER // for MS Visual Studio classname = classname.substr(6); #else // for other compilers classname = classname.substr(classname.find_first_not_of("0123456789")); #endif return classname; } RectangularPrism::RectangularPrism(double length, double width, double height) : length_(length), width_(width), height_(height) { } double RectangularPrism::volume() const { return length_ * width_ * height_; } Cube::Cube(double s) : RectangularPrism(s, s, s) { } Circular::Circular(double radius) : radius_(radius) { } double Circular::radius() const { return radius_; } Cylinder::Cylinder(double radius, double height) : Circular(radius), height_(height) { } Sphere::Sphere(double radius) : Circular(radius) { } double Cylinder::volume() const { return PI * radius_ * radius_ * height_; } double Sphere::volume() const { return 4. / 3. * PI * radius_ * radius_ * radius_; } ColoredThing::ColoredThing(double weight, string color) : color_(color), weight_(weight) { } string ColoredThing::color() const { return color_; } ColoredCylinder::ColoredCylinder(double radius, double height, double weight, string color) : Cylinder(radius, height), ColoredThing(weight, color) { } ColoredSphere::ColoredSphere(double radius, double weight, string color) : Sphere(radius), ColoredThing(weight, color) { } double ColoredSphere::density() const { return weight_ / volume(); } double ColoredCylinder::density() const { return weight_ / volume(); } ColoredRectangularPrism::ColoredRectangularPrism(double length, double width, double height, double weight, string color) : RectangularPrism(length, width, height), ColoredThing(weight, color) { } double ColoredRectangularPrism::density() const { return weight_ / volume(); } ostream& operator<<(ostream& out, const GeometricSolid& S) { if (S.volume() < 0) throw range_error("Invalid volume for " + S.name() + ": " + to_string(S.volume())); out << left << setw(24) << S.name() << right << setw(12) << S.volume(); return out; } ColoredCube::ColoredCube(double side, double weight, string color) : Cube(side), ColoredThing(weight, color) { } double ColoredCube::density() const { return weight_ / volume(); } ostream& operator<<(ostream& out, const ColoredThing& CT) { out << ' ' << left << setw(8) << CT.color() << right << setw(12) << CT.density(); return out; } ostream& operator<<(ostream& out, const Thing& object) { const GeometricSolid* ptrGeometricSolid = dynamic_cast(&object); const ColoredThing* ptrColoredThing = dynamic_cast(&object); if (ptrGeometricSolid) { out << (*ptrGeometricSolid); } if (ptrColoredThing) { out << (*ptrColoredThing); } return out; }