【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++的继承
【C++】详解C++的继承
|
7天前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
13 3
|
3天前
|
C++
c++继承层次结构实践
这篇文章通过多个示例代码,讲解了C++中继承层次结构的实践应用,包括多态、抽象类引用、基类调用派生类函数,以及基类指针引用派生类对象的情况,并提供了相关的参考链接。
|
28天前
|
C++
C++(二十)继承
本文介绍了C++中的继承特性,包括公有、保护和私有继承,并解释了虚继承的作用。通过示例展示了派生类如何从基类继承属性和方法,并保持自身的独特性。此外,还详细说明了派生类构造函数的语法格式及构造顺序,提供了具体的代码示例帮助理解。
|
2月前
|
存储 算法 C++
C++ STL应用宝典:高效处理数据的艺术与实战技巧大揭秘!
【8月更文挑战第22天】C++ STL(标准模板库)是一组高效的数据结构与算法集合,极大提升编程效率与代码可读性。它包括容器、迭代器、算法等组件。例如,统计文本中单词频率可用`std::map`和`std::ifstream`实现;对数据排序及找极值则可通过`std::vector`结合`std::sort`、`std::min/max_element`完成;而快速查找字符串则适合使用`std::set`配合其内置的`find`方法。这些示例展示了STL的强大功能,有助于编写简洁高效的代码。
34 2
|
2月前
|
存储 搜索推荐 Serverless
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
29 1
|
2月前
|
编译器 C++
C++的基类和派生类构造函数
基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。 在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。 这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。 下面的例子展示了如何在派生类的构造函数中调用基类的构造函数:
31 1
|
2月前
|
存储 编译器 C++
C++多态实现的原理:深入探索与实战应用
【8月更文挑战第21天】在C++的浩瀚宇宙中,多态性(Polymorphism)无疑是一颗璀璨的星辰,它赋予了程序高度的灵活性和可扩展性。多态允许我们通过基类指针或引用来调用派生类的成员函数,而具体调用哪个函数则取决于指针或引用所指向的对象的实际类型。本文将深入探讨C++多态实现的原理,并结合工作学习中的实际案例,分享其技术干货。
53 0
|
2月前
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
|
2月前
|
安全 Java 编译器