假设我想定义一个名为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
我不太确定两件事:
我应该向Shape
班级添加c&#39}和<&strong>
据我了解,因为该类是抽象的,所以没有必要。
我应该将override
添加到Circle
中被覆盖的方法,就像这样吗?
virtual double getArea() const override ;
virtual double getPerim() const override ;
假设我写了以下内容(主要内容):
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&lt;
的需要?答案 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;正在使用。当你知道你没有做到这一点时非常有帮助!