使用c' ctor,d' ctor并覆盖

时间:2017-12-20 19:48:11

标签: c++ class polymorphism override

假设我想定义一个名为Circle的类,它有计算其面积和周长的方法。此类使用另一个名为Point的类。还假设此类继承自名为Shape的抽象类。

所以,我写了下面的代码:

circle.h

#ifndef Circle_h
#define Circle_h
#include "Point.h"
#include "Shape.h"

class Circle : public Shape
{
public:

    Circle(const Point &ceneter , int radius);
    ~Circle();

    virtual double getArea() const ;
    virtual double getPerim() const ;

private:
    int radius;
    Point center;
};

#endif 

shape.h

#ifndef Shape_h
#define Shape_h
#include "Point.h"
#include <iostream>

class Shape          //abstract class//
{
public:

    virtual double getArea() const=0;
    virtual double getPerim() const=0;
};

#endif 

point.h

#ifndef Point_h
#define Point_h

class Point
{
public:

    Point(int x, int y);
    ~Point();

    int getX() const;
    int getY() const;

    void setX(int x);
    void setY(int y);

private:

    int x, y;
};

#endif 

我不太确定两件事:

  1. 我应该向Shape班级添加c&#39}和<&strong>

    据我了解,因为该类是抽象的,所以没有必要。

  2. 我应该将override添加到Circle中被覆盖的方法,就像这样吗?

    virtual double getArea() const override ;
    virtual double getPerim() const override ;
    
  3. 假设我写了以下内容(主要内容):

    Point o(0, 0);
    
    Point a(0, 1);
    
    Point b(1, 0);
    
    Shape *shapes[] = { new Circle(a, 2), new Circle(b,3), new Circle(o, 1 };
    
  4. 最后一行如何影响使用(或不使用)c&tor; d&lt;

    的需要?

3 个答案:

答案 0 :(得分:1)

您的Shape课程不需要ctor,但建议给它virtual dtor:

class Shape {
public:
    virtual ~Shape() = default;
    // ...
};

没有这个virtual析构函数,delete对象通过指向Shape的指针是未定义的行为:没有具体类型可以是动态类型Shape但是{{1当dtor不是delete时,通过具有不同静态类型的指针的对象是未定义的行为。

关于virtual的使用我推荐使用它!虽然在一个简单的例子中它可能并不重要,例如你展示的那个,它会在类层次结构增长时变得相关。任何成功的软件都会增长,它会增加override个功能,代码清晰度有助于维护。 ......我更愿意为成功做好准备。

答案 1 :(得分:0)

如上所述,这些类都不需要复制构造函数或析构函数。这是因为所有成员都是简单的值,除了值复制之外不需要任何其他值,或者只需要释放内存。

当类具有编译器无法知道如何释放的资源(例如文件句柄)时,需要dtor。

答案 2 :(得分:0)

  

我应该向Circle中的重写方法添加覆盖,像这样吗?

恕我直言,这个词增加了价值。

  

假设我写了以下内容(主要内容):

Point o(0, 0); 
Point a(0, 1); 
Point b(1, 0); 
Shape* shapes[] = { new Circle(a, b), 
                    new Circle(o, a, b), 
                    new Circle(o, 1) };

使用这些行,我的编译器现在报告另外2个错误(带有2个音符)......

error: no matching function for call to ‘Circle::Circle(Point&, Point&)’
note:   no known conversion for argument 2 from ‘Point’ to ‘int’

error: no matching function for call to ‘Circle::Circle(Point&,Point&,Point&)’
note:   candidate expects 2 arguments, 3 provided
  

最后一行是否会影响使用(或不使用)c&tor; tor&d?tor的需要?

我想不是。

即使在此之前添加代码&#39;编译器发出有关具有虚拟功能和可访问的非虚拟d的警告。这些警告可以通过声明(丢失)dtors虚拟来修复,但是......好吧,这里他们只是指出你的代码编译不干净。

您应该完成[MCVE]。因此,您提供的信息不足以提供谨慎的选择。你做什么或不提供什么(ctors,dtors)。

我通常以另一种方式来解决这些问题。我的个人编码&#39;标准&#39;包括以下6个想法,当我有疑问或者不明白为什么时,我只是将这些行添加到我的课程中,在私人部分。

  //  coding standard: disallow when not used
  T(void)                  = delete; // default ctor    (1)
 ~T(void)                  = delete; // default dtor    (2)
  T(const T&)              = delete; // copy ctor       (3)
  T(const T&&)             = delete; // move ctor       (4)
  T& operator= (const T&)  = delete; // copy assignment (5)
  T& operator= (const T&&) = delete; // move assignment (6)

由T&#39;,我的意思是你替换&#39; T&#39;用你的班级名字。它很简单,所以我通常会添加到每个类中。即在每个班级的私人区域重复上述6行,并更换T。

现在,您的编译器可能会抱怨特定的内容。我发现很快就能学会如何解决这个问题,所以我举了一个例子。

如果您获得MCVE,请尝试以下添加:

class Shape          //abstract class//
{
public:
    virtual double getArea() const=0;
    virtual double getPerim() const=0;

private:
   // coding standard - disallow when not used
   Shape(void)                      = delete; // default ctor    (1)
  ~Shape(void)                      = delete; // default dtor    (2)
   Shape(const Shape&)              = delete; // copy ctor       (3)
   Shape(const Shape&&)             = delete; // move ctor       (4)
   Shape& operator= (const Shape&)  = delete; // copy assignment (5)
   Shape& operator= (const Shape&&) = delete; // move assignment (6)
};

由于Shape类只有编译器注入了默认的ctor,(和dtor),我认为这些删除会在编译器中触发错误。

这个想法很简单,如果&#39;其他代码&#39; (例如标准容器,算法或编译器)使用Shape做一些事情并使用一个或添加其中一个或多个,编译器会注意到它们被删除,并为您生成错误。

我对标准容器感到惊讶,因为他们经常使用这些容器中的6个以上。删除ctor后,我有机会决定是否要编写特定于此项工作的内容,或者如果编译器提供的默认值可能正常......通常是这样。在这种情况下,我只是注释掉6个删除行中的一个或多个,然后再次编译。

我拒绝评论这些删除。有时会发生我的一个错误会触发6个中的一个使用。也要注意那些。

  • 摘要

这6行(以及您可能选择考虑的其他内容)将让您了解编译器作为“服务”提供的方法。 (大多数时候,我也不喜欢隐含的转换。)

所以,不要试图理解为什么你可能想要或不想要这些6,这种技术可以让你找出你的程序需要什么。使用每一行(即禁用至少足够长的时间以查看位置和内容),编译器投诉会显示“ctor&#39;或者&#39;移动作业&#39;正在使用。当你知道你没有做到这一点时非常有帮助!