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

问题描述 投票:0回答:3

假设我想定义一个名为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'tor和d'ctor吗? 因为据我所知,因为那个类是抽象的,所以没有必要。
  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 };

最后一行如何影响使用(或不使用)ctor和dtor的需要?

c++ class polymorphism override
3个回答
1
投票

你的Shape课程不需要ctor但是建议给它一个virtual dtor:

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

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

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


0
投票

如上所述,这些类都不需要复制构造函数或析构函数。这是因为所有成员都是简单的值,不需要任何更多的值副本或简单地释放内存。

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


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和d'tor的需要?

我想不是。

甚至在此“代码添加”之前,编译器就会提供有关虚拟功能和可访问的非虚拟代码的警告。这些警告可以通过声明(丢失)dtors虚拟来修复,但是......好吧,这里他们只是指出你的代码编译不干净。


你应该完成你的[MCVE]。因此,您提供的信息不足以“仔细挑选”您所做或不提供的内容(ctors,dtors)。

我通常以另一种方式来解决这些问题。我的个人编码“标准”包括以下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',我的意思是你用你的班级名称替换'T'。它很简单,所以我通常会添加到每个类中。即,在每个类的私人区域中重复上述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)我认为这些删除会在编译器中触发错误。

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

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

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

  • 摘要

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

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

© www.soinside.com 2019 - 2024. All rights reserved.