C++ 几何层次结构、类向上转换和继承

Posted

技术标签:

【中文标题】C++ 几何层次结构、类向上转换和继承【英文标题】:C++ Geometry hierarchy, Class upcasting and inheritance 【发布时间】:2020-12-17 23:55:10 【问题描述】:

我正在做一个理解类的项目,但遇到了困难。如果您对我的语法有任何建议,请让我知道我哪里出错了,因为我对编程还是很陌生,但我的问题是与类继承有关。 (包括 A、C 和 D,但完成得相当好)。

我的项目:

A.从点类开始...覆盖

B.创建一个基类 Shape。 Shape 将包含计算面积、周长和取点值的函数,以创建一个封装给定形状的框。这些将被派生类重载。创建一个显示所有相关信息(名称、面积、周长和封装框)的 display() 函数。

C.通过制作圆形、方形、三角形来构建形状的层次结构......添加默认和自定义构造函数,其参数使用正确数量的点对象初始化形状。我觉得我也很满意。

D.在 main() 中创建每个实例。圆半径 = 到 23,每个正方形边 = 25,三角形边 = 10、20 和 30(非常平坦的三角形,面积 = 0)。定义每个包含原点 (0, 0)。显示所有信息。我觉得我已经完成了这个(减去显示功能)。

我的问题是(以及我在哪里苦苦挣扎),“我如何正确地从基类(形状)创建/访问函数以返回有意义的信息。”

我是否真的只是将它们全部设为虚拟,因为某些类没有与其他类相同的信息? (比如 Area() 和 Circumference()?)

#include <iostream> 
#include <cmath>
using namespace std;

class Point 
public:
  int x, y;
    Point() 
    x = 0;
    y = 0;
    
    Point(int x, int y): x(x), y(y)  // constructor

    friend ostream& operator<<(ostream& out, const Point number)     //Involves ostream to output the numbers
        out << "(" << number.x << ", " << number.y << ")";  //that were input into the x and y values of Point.
    return out;
    
    friend Point operator+(Point first, Point second)    //Takes two mathematical vectors and tells the compiler
    Point add;                                  // to add the x values together and the y values together
    add.x = first.x + second.x;
    add.y = first.y + second.y;
    return add; 
    
    friend Point operator-(Point first, Point second)    // same as above but with subtraction.
    Point subtract;
    subtract.x = first.x - second.x;
    subtract.y = first.y - second.y;
    return subtract;
  
;

class Shape 
protected:
  float height, width;
public:
  Shape() 
    height = 0;
    width = 0;
  
  Shape(float h, float w) 
    height = h;
    width = w;
  
  /*
  int Display() 
    //Do something..... Create a display function
    return 0;
  
  int BoundingBox() 
    //Do something again......
    return 0;
  
  */
  virtual float Area() const = 0;
  virtual float Circumference() const = 0;

  virtual ~Shape()  ;
;

class Circle: public Shape  
  Point center;
  float radius;
public:
  Circle(): Shape()  ;
  Circle (Point p1, float r)   //Takes center point object, and given radius.
    center = p1;
    radius = r;
  
  virtual float Area() const override  // Calculates circle area
      return(M_PI * radius * radius);
  
  virtual float Circumference() const override  // Calculates circumference
    return(float (M_PI * 2 * radius));
  
  virtual ~Circle() ;
;

class Square: public Shape  
  Point first, second, third, fourth;
public:
  Square(): Shape()  ;
  Square(Point p1, Point p2, Point p3, Point p4)  // Takes four point arguments and initializes them
    first = p1;
    second = p2;
    third = p3;
    fourth = p4;
    height = second.x - first.x; //calculates the height and width from points
    width = third.y - first.y;
  
  virtual float Circumference() const override  
    return 0; //Errors without the return statement
  
  virtual float Area() const override // Calculates area by measuring the difference between given points
    return(height * width);
  
  virtual ~Square() ;
;

class Triangle: public Shape    
  Point first, second, third;
public:
  Triangle(): Shape()  ;
  Triangle(Point p1, Point p2, Point p3)   // Takes three point arguments and initializes them
    first = p1;
    second = p2;
    third = p3;
    height = third.y - first.y;// due to the nature of the question, this only works for flat triangles.
    width = second.x - first.x;
  
  virtual float Circumference() const override  
    return 0; //Errors without the return statement
  
  virtual float Area() const override  
    return ((height * width) / 2);
  
  virtual ~Triangle() ;
;


int main()  
  Point p1(0, 0), p2(25, 0), p3(0, 25), p4(25, 25), p5(20, 0), p6(30, 0);
  Circle c1 (p1, 23); // Circle with origin (0, 0) and a radius of 23
  Square s1 (p1, p2, p3, p4); // Square with 4 points and the origin
  Triangle t1 (p1, p5, p6); // Extraordinarily flat triangle with origin
  cout << c1.Circumference() << endl;
  cout << s1.Area() << endl;
  cout << t1.Area() << endl;

在这一点上,我感到有点迷失了方向,我确信我在此过程中要么犯了几个错误,要么只是犯了几个错误,但无论如何,我不明白。任何建议将不胜感激!

编辑:我已经更新了我的代码,以包括包含虚拟解构函数、删除 getheight 等...语句以及将虚拟添加到派生函数的建议

【问题讨论】:

你到底为什么要使用friend作为公共方法? 因为我不这样做时整个程序都会中断... 【参考方案1】:

    当您使用继承时,请确保在所有继承类以及基类中使用虚拟析构函数。

    如果您想进行进一步的专业化,您继承的虚函数也将受益于标记virtualoverride

    您正在覆盖继承的函数,但它们的作用与原始函数相同,例如GetHeight()。这有点违背了继承这些功能的意义。如果它们没有被覆盖,它们也不需要是虚拟的。

    您的派生类将受益于显式调用基类的构造函数。如果您不提供要调用的特定构造函数,它将调用默认构造函数,这可能是也可能不是您想要的行为 - IMO 始终提供您想要的基类构造函数更安全!

举个例子:

class Shape 

protected:
  float height, width;

public:
  Shape() 
    height = 0;
    width = 0;
  

  Shape(float h, float w) 
    height = h;
    width = w;
  

  virtual float Area() const = 0;
  virtual float Circumference() const = 0;
  
  virtual ~Shape()  ;
;

class Circle: public Shape  
  Point center;
  float radius;

public:
  Circle() : Shape() ;

  Circle (Point p1, float r) : Shape()  

  // Note you may wish to set the height and width here!

  //Takes center point object, and given radius.
    center = p1;
    radius = r;
  

  virtual float Area() const override  // Calculates circle area
      return(M_PI * radius * radius);
  

  virtual float Circumference() const override  // Calculates circumference
    return(float (M_PI * 2 * radius));
  

  virtual ~Circle() ;
;

【讨论】:

好的,谢谢!我已经更改了我的代码,并且收到了与我对正方形和三角形圆周的不良修复之前相同的错误。 /usr/bin/ld: /tmp/ccgy05RH.o: 在函数Square::Square(Point, Point, Point, Point)': TMA3Question3.cpp:(.text._ZN6SquareC2E5PointS0_S0_S0_[_ZN6SquareC5E5PointS0_S0_S0_]+0x2f): undefined reference to vtable for Square' /usr/bin/ld: /tmp/ccgy05RH.o: 在函数Square::~Square()': TMA3Question3.cpp:(.text._ZN6SquareD2Ev[_ZN6SquareD5Ev]+0x13): undefined reference to vtable for Square' /usr/bin/ld: /tmp/ccgy05RH.o: 在函数Triangle::Triangle(Point, Point, Point)': TMA3Question3.cpp:(.text._ZN8TriangleC2E5PointS0_S0_[_ZN8TriangleC5E5PointS0_S0_]+0x2b): undefined reference to vtable for Triangle' /usr/bin/ld: /tmp/ccgy05RH.o: 在函数Triangle::~Triangle()': TMA3Question3.cpp:(.text._ZN8TriangleD2Ev[_ZN8TriangleD5Ev]+0x13): undefined reference to Triangle'collect2 的 vtable:错误:ld 返回 1 个退出状态 已更新以反映您的建议! (再次感谢!)

以上是关于C++ 几何层次结构、类向上转换和继承的主要内容,如果未能解决你的问题,请参考以下文章

向上强制转换和向下强制转换

C++的探索路11继承与派生之拓展篇--多形式派生以及派生类指针转换

C++继承

C++继承

C++:派生模板类和基类之间的向下转换和向上转换?

C++中 OOP相关的类型转换