使用 c'ctor、d'ctor 和 override

using c'ctor, d'ctor and override

本文关键字:ctor override 使用      更新时间:2023-10-16

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

因此,我编写了以下代码:

圆圈.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 

形状.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 

点.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. 我应该像这样在Circle中被覆盖的方法中添加override吗?

    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 };
    

最后一行如何影响使用(或不使用)c'tor和d'tor的需求?

你的Shape类不需要 ctor,但给它一个virtualdtor 是可见的:

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

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

关于override的使用,我建议使用它!虽然在像您展示的简单示例中可能无关紧要,但当类层次结构增长时,它将变得相关。任何成功的软件都会增长,它将增加virtual功能和代码清晰度有助于维护。...我更喜欢为成功做计划。

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

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

我应该像这样在 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 的需求?

我认为不是。

甚至在这种"代码添加"之前,编译器就会发出有关具有虚拟函数和可访问的非虚拟 d'tor 的警告。 这些警告可以通过声明(丢失的)dtor 虚拟来修复,但是......好吧,在这里他们只是指出您的代码编译不干净。


您应该完成您的 [MCVE]。 照原样,您提供的信息不足以"仔细选择"您提供或不提供的内容(ctors,dtor)。

我通常以另一种方式来解决这些问题。 我的个人编码"标准"包括以下 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 个中的一个或多个,编译器会注意到它们被删除,并为您生成错误。

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

我拒绝注释掉这些删除。 有时,我的一个错误会触发对 6 个错误之一的使用。 也必须注意那些。

  • 总结

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

因此,与其试图理解为什么你可能想要或不想要这 6 个,这种技术可以让您找出您的程序需要什么。 使用每一行(即至少禁用足够长的时间以查看位置和目的),编译器投诉显示"移动ctor"或"移动赋值"的使用位置。 当你知道你没有这样做时,非常有帮助!