【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 中。


相关文章
|
11天前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
44 16
|
8天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
28 5
|
2月前
|
编译器 C++ 开发者
【C++】继承
C++中的继承是面向对象编程的核心特性之一,允许派生类继承基类的属性和方法,实现代码复用和类的层次结构。继承有三种类型:公有、私有和受保护继承,每种类型决定了派生类如何访问基类成员。此外,继承还涉及构造函数、析构函数、拷贝构造函数和赋值运算符的调用规则,以及解决多继承带来的二义性和数据冗余问题的虚拟继承。在设计类时,应谨慎选择继承和组合,以降低耦合度并提高代码的可维护性。
39 1
【C++】继承
|
3月前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
3月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
101 11
|
3月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
70 1
|
3月前
|
C++
C++番外篇——虚拟继承解决数据冗余和二义性的原理
C++番外篇——虚拟继承解决数据冗余和二义性的原理
54 1
|
3月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
93 2
|
4月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
37 3
|
3月前
|
安全 编译器 程序员
C++的忠实粉丝-继承的热情(1)
C++的忠实粉丝-继承的热情(1)
25 0

热门文章

最新文章