【C++综合设计题】多层继承和抽象基类的综合应用

简介: 【C++综合设计题】多层继承和抽象基类的综合应用

题目要求


首先,声明一组多层继承关系的形状类族。从最抽象、最顶层的基类SHAPE(形状)开始,逐级向下派生出的各级子类依次为:POINT、LINE//CURVE、……、CUBE//CUBOID//DAM。详细的派生关系如下图所示。



具体的设计要求如下:

 通过键盘输入三角形的顶点:(0,0)、(5,0)、(3,6),输出其周长和面积;

 通过键盘输入正方形边长(9)和长方形边长(9、5),输出其周长和面积;

 通过键盘输入一个梯形坝体截面的顶点坐标:(0,0)、(2,4)、(6,4)、(8,

0)和坝体长度:28,输出其表面积和体积;

 通过键盘输入一圆柱体的截面半径(3)和高度(9),输出其表面积和体积;

 将上述输入和输出数据以文本形式保存至当前目录下的一个磁盘文件中。

——输出格式如下:


1)三角形数据

其顶点坐标为:

其周长为:

其面积为:


2)正方形数据

其边长为:

其周长为:

其面积为:


3)长方形数据

其边长为:

其周长为:

其面积为:


4)梯形坝体数据

其梯形顶点坐标为:

其坝体长度为:

其表面积为:

其体积为:


5)圆柱体数据

其截面半径为:

其柱体高度为:

其表面积为:

其体积为:


思路


首先厘清各个类之间的关系,确定继承和派生关系。为了建立一个公共的SHAPE类接口,使它们能够更有效地发挥多态特性,可以将 SHAPE 类作为抽象基类,将计算周长、面积、表面积和体积的函数设为虚函数,在派生类中根据需要对虚函数进行重定义。


如果对抽象基类不太熟悉,可以参考下面的博客:

【C++之纯虚函数与抽象类1】圆形、矩形、三角形的面积


为使程序整洁,我主要定义三角形、正方形、长方形、梯形和圆柱体的数据计算函数以及信息展示函数。根据输入数据的不同,设计周长、面积、表面积和体积的计算公式。


除了设计各种形状的类,完成相应数据计算,本题还需要从键盘输入各个形状原始数据,并将计算结果输出至磁盘文件中。


如果对标准输入输出流或文件流不太熟悉,可以参考下面的博客:

【C++之标准输入输出流】 判断是否符合条件并计算三角形的面积

【C++之文件与文件流】f1.dat 和 f2.dat 文件的读写


程序


/*
*************************************************************************
@file:    T5.cpp
@date:   2021.1.20
@author: Xiaoxiao
@brief:   多层继承和抽象基类的综合应用项目
@blog:    https://blog.csdn.net/weixin_43470383/article/details/112905064
*************************************************************************
*/
#include <iostream>
#include<fstream>
#include <math.h>
using namespace std;
// 形状
class SHAPE 
{
public:
  virtual float Perimeter() { return 0.0; } // 虚函数:计算周长
  virtual float Area() { return 0.0; } // 虚函数:计算面积
  virtual float Surface_area() { return 0.0; } // 虚函数:计算表面积
  virtual float Volume() { return 0.0; } // 虚函数:计算体积
};
// 点
class POINT :public SHAPE 
{
public:
  POINT() { px = 0; py = 0; }
  POINT(int x, int y) :px(x), py(y) {}; // 构造函数
  int px;
  int py;
};
// 直线
class LINE :public POINT 
{
public:
  LINE() { }
  LINE(POINT x, POINT y) :pt1(x), pt2(y) {}; // 构造函数
  float Length(POINT x, POINT y)
  {
  return sqrt(pow((x.px - y.px), 2) + pow((x.py - y.py), 2));
  }
  POINT pt1;
  POINT pt2;
};
// 三角形
class TRIANGLE :public LINE 
{
public:
  TRIANGLE(){}
  TRIANGLE(POINT x, POINT y, POINT z) :a(x), b(y), c(z) {}; // 定义构造函数
  virtual float Perimeter(POINT x, POINT y, POINT z) // 对虚函数再定义
  {
  return Length(a, b) + Length(b, c) + Length(a, c);
  }
  virtual float Area(POINT x, POINT y, POINT z) // 对虚函数再定义
  {
  return (1.0 / 4) * pow((Length(a, b) + Length(b, c) + Length(a, c))*(Length(a, b) + Length(b, c) - Length(a, c))
    *(Length(a, b) + Length(a, c) - Length(b, c))*(Length(b, c) + Length(a, c) - Length(a, b)), 0.5);
  }
  POINT a;
  POINT b;
  POINT c;
};
// 棱柱体
class PRISMOID :public TRIANGLE 
{
public:
  PRISMOID(POINT x, POINT y, POINT z, int he) :TRIANGLE(x, y, z),height(he){}; // 定义构造函数
  POINT a;
  POINT b;
  POINT c;
  int height;
};
// 四边形
class QUADRANGLE :public LINE 
{
public:
  QUADRANGLE() {}
  QUADRANGLE(POINT w, POINT x, POINT y, POINT z) :a(w), b(x), c(y), d(z) {}; // 定义构造函数
  POINT a;
  POINT b;
  POINT c;
  POINT d;
};
// 正方形
class SQUARE :public QUADRANGLE 
{
public:
  SQUARE() {};
  SQUARE(int a) :len(a){}; // 定义构造函数
  virtual float Perimeter(int a) // 对虚函数再定义
  {
  return 4 * a;
  }
  virtual float Area(int a) // 对虚函数再定义
  {
  return a * a;
  }
  int len;
};
// 正方体
class CUBE :public SQUARE 
{
public:
  CUBE() {}
  CUBE(POINT w, POINT x, POINT y, POINT z) :a(w), b(x), c(y), d(z) {}; // 定义构造函数
  POINT a;
  POINT b;
  POINT c;
  POINT d;
}; 
// 长方形
class RECTANGLE :public QUADRANGLE 
{
public:
  RECTANGLE() {};
  RECTANGLE(int a, int b) :height(a), width(b) {}; // 定义构造函数
  virtual float Perimeter(int a, int b) // 对虚函数再定义
  {
  return 2 * (a + b);
  }
  virtual float Area(int a, int b) // 对虚函数再定义
  {
  return a * b;
  }
  int width;
  int height;
};
// 长方体
class CUBOID :public RECTANGLE 
{
public:
  CUBOID() {}
  CUBOID(POINT w, POINT x, POINT y, POINT z) :a(w), b(x), c(y), d(z) {}; // 定义构造函数
  POINT a;
  POINT b;
  POINT c;
  POINT d;
};
// 梯形
class TRAPEZOID :public QUADRANGLE 
{
public:
  TRAPEZOID() {};
  TRAPEZOID(POINT w, POINT x, POINT y, POINT z) :QUADRANGLE(w, x, y, z) {}; // 定义构造函数
  virtual float Area(POINT a, POINT b, POINT c, POINT d) // 对虚函数再定义
  {
  return (Length(a,d)+Length(b, c))*(b.py-a.py)/2; // 注意顺序
  }
  POINT a;
  POINT b;
  POINT c;
  POINT d;
};
// 坝体
class DAM :public TRAPEZOID 
{
public:
  DAM(POINT w, POINT x, POINT y, POINT z, int len) :a(w), b(x), c(y), d(z), length(len) {}; // 定义构造函数
  virtual float Surface_area(POINT w, POINT x, POINT y, POINT z, int len) // 对虚函数再定义
  {
  return 2 * Area(w, x, y, z) + Length(w, x)*len + Length(y, z) * len + Length(w, z) * len + Length(x, y) * len;
  }
  virtual float Volume(POINT w, POINT x, POINT y, POINT z, int len) // 对虚函数再定义
  {
  return len * Area(w, x, y, z);
  }
  POINT a;
  POINT b;
  POINT c;
  POINT d;
  int length;
};
// 曲线
class CURVE :public POINT 
{
public:
  CURVE() { }
};
// 圆形
class CIRCLE :public CURVE 
{
public:
  CIRCLE() { }
  CIRCLE(int r) :radius(r) {}; // 定义构造函数
  virtual float Area(int r) // 对虚函数再定义
  {
  return 3.14159 * r * r;
  }
  int radius;
}; 
// 圆柱体
class CYLINDER :public CIRCLE 
{
public:
  CYLINDER(int r, int h) :radius(r) ,height(h) {}; // 定义构造函数
  virtual float Surface_area(int r, int h) // 对虚函数再定义
  {
  return 2 * Area(r) + 2 * 3.14159 * r * h ;
  }
  virtual float Volume(int r, int h) // 对虚函数再定义
  {
  return Area(r) * h;
  }
  int radius;
  int height;
};
int main()
{
  fstream outfile; // 定义文件流对象
  outfile.open("f1.dat", ios::out); // f1.dat 为输出文件
  if (!outfile)
  {
  cerr << "f1.dat open error!" << endl; // 检查打开 f1.dat 是否成功
  exit(1);
  }
  // 三角形顶点
  POINT pt1, pt2, pt3;
  cout << "输入三角形顶点坐标" << endl;
  cout << "输入第一个顶点的坐标:" << endl;;
  cin >> pt1.px >> pt1.py;
  cout << "输入第二个顶点的坐标:" << endl;;
  cin >> pt2.px >> pt2.py; 
  cout << "输入第三个顶点的坐标:" << endl;;
  cin >> pt3.px >> pt3.py; 
  // 正方形边长
  int length1;
  cout << "输入正方形的边长" << endl;
  cin >> length1;
  // 长方形边长
  int height, width;
  cout << "输入长方形的高" << endl;
  cin >> height;
  cout << "输入长方形的宽" << endl;
  cin >> width;
  // 梯形坝体顶点和长度
  POINT pt4, pt5, pt6, pt7;
  int length2;
  cout << "输入梯形顶点坐标" << endl;
  cout << "输入第一个顶点的坐标:" << endl;;
  cin >> pt4.px >> pt4.py;
  cout << "输入第二个顶点的坐标:" << endl;;
  cin >> pt5.px >> pt5.py;
  cout << "输入第三个顶点的坐标:" << endl;;
  cin >> pt6.px >> pt6.py;
  cout << "输入第四个顶点的坐标:" << endl;;
  cin >> pt7.px >> pt7.py;
  cout << "输入梯形坝体的长度" << endl;
  cin >> length2;
  // 圆柱体截面半径和柱体高度
  int radius, height2;
  cout << "输入圆柱体截面半径" << endl;
  cin >> radius;
  cout << "输入圆柱体柱体高度" << endl;
  cin >> height2;
  // 定义三角形、正方形、长方形、梯形对象
  TRIANGLE triangle(pt1, pt2, pt3);
  SQUARE square(length1);
  RECTANGLE rectangle(height, width);
  DAM dam(pt4, pt5, pt6, pt7, length2);
  CYLINDER cylinder(radius, height2);
  outfile << "1)三角形数据" << endl;
  outfile << "其顶点坐标为:" << "(" << pt1.px << "," << pt1.py << ") "
    << "(" << pt2.px << "," << pt2.py << ") " << "(" << pt3.px << "," << pt3.py << ")" << endl;
  outfile << "其周长为:" << triangle.Perimeter(pt1, pt2, pt3) << endl;
  outfile << "其面积为:" << triangle.Area(pt1, pt2, pt3) << endl << endl;
  outfile << "2)正方形数据" << endl;
  outfile << "其边长为:" << length1 << endl;
  outfile << "其周长为:" << square.Perimeter(length1) << endl;
  outfile << "其面积为:" << square.Area(length1) << endl << endl;
  outfile << "3)长方形数据" << endl;
  outfile << "其边长为:" << height << ", " << width << endl;
  outfile << "其周长为:" << rectangle.Perimeter(height, width) << endl;
  outfile << "其面积为:" << rectangle.Area(height, width) << endl << endl;
  outfile << "4)梯形坝体数据" << endl;
  outfile << "其梯形顶点坐标为:" << "(" << pt4.px << "," << pt4.py << ") " << "(" << pt5.px << "," << pt5.py << ") "
  << "(" << pt6.px << "," << pt6.py << ") " << "(" << pt7.px << "," << pt7.py << ")" << endl;
  outfile << "其坝体长度为:" << length2 << endl;
  outfile << "其表面积为:" << dam.Surface_area(pt4, pt5, pt6, pt7, length2) << endl;
  outfile << "其体积为:" << dam.Volume(pt4, pt5, pt6, pt7, length2) << endl << endl;
  outfile << "5)圆柱体数据" << endl;
  outfile << "其截面半径为:" << radius << endl;
  outfile << "其柱体高度为:" << height << endl;
  outfile << "其表面积为:" << cylinder.Surface_area(radius, height) << endl;
  outfile << "其体积为:" << cylinder.Volume(radius, height) << endl << endl;
  return 0;
}


运行结果


从键盘输入原始数据:




关闭运行窗口,数据被输入到 f1.dat 中。


相关文章
|
3天前
|
存储 编译器 C++
C++程序变量存储类别:深入理解与应用
C++程序变量存储类别:深入理解与应用
16 1
|
3天前
|
存储 C++
C++程序全局变量:理解与应用
C++程序全局变量:理解与应用
10 0
|
3天前
|
C++
C++程序中的继承与组合
C++程序中的继承与组合
11 1
|
8天前
|
安全 前端开发 Java
【C++】从零开始认识继承二)
在我们日常的编程中,继承的应用场景有很多。它可以帮助我们节省大量的时间和精力,避免重复造轮子的尴尬。同时,它也让我们的代码更加模块化,易于维护和扩展。可以说,继承技术是C++的灵魂。
15 1
|
8天前
|
安全 程序员 编译器
【C++】从零开始认识继承(一)
在我们日常的编程中,继承的应用场景有很多。它可以帮助我们节省大量的时间和精力,避免重复造轮子的尴尬。同时,它也让我们的代码更加模块化,易于维护和扩展。可以说,继承技术是C++的灵魂。
25 3
【C++】从零开始认识继承(一)
|
2天前
|
编译器 C++
【继承】初步了解C++继承
【继承】初步了解C++继承
|
2天前
|
存储 设计模式 编译器
【C++】继承和多态常见的问题
【C++】继承和多态常见的问题
|
2天前
|
存储 Java 编译器
【C++】继承 -- 详解(下)
【C++】继承 -- 详解(下)
|
2天前
|
安全 编译器 程序员
【C++】继承 -- 详解(上)
【C++】继承 -- 详解(上)
|
3天前
|
安全 程序员 编译器
C++程序中的基类与派生类转换
C++程序中的基类与派生类转换
8 1