使用 c'ctor、d'ctor 和 override
using c'ctor, d'ctor and override
假设我想定义一个名为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
我对两件事不太确定:
我应该在
Shape
类中添加 c'tor 和 d'ctor 吗?因为据我了解,由于该类是抽象的,因此不需要它们。
我应该像这样在
Circle
中被覆盖的方法中添加override
吗?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'tor的需求?
你的Shape
类不需要 ctor,但给它一个virtual
dtor 是可见的:
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"或"移动赋值"的使用位置。 当你知道你没有这样做时,非常有帮助!
- 如何确保C++函数在定义之前声明(如override关键字)
- std::is_base_of表示ctor编译错误
- 对复制 CTOR 和 CTOR 的未定义引用
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- C++成功复制动态分配的 obj 而不复制 ctor?
- 如何测试采用 std::initializer_list 的 ctor 具有编译时已知长度?
- C++类:virtual和override,或者两者都没有
- 如何在 CMake 中"override"文件的按扩展名类型
- 使用<<自有函数的运算符来"override" cout
- 为什么 std::optional::value_or 没有默认 ctor 类型的专用化?
- 在CTOR vs Connect方法中提升套接字与stream_socket端点
- 给定一个右值,为什么移动ctor比常量复制ctor更匹配
- std::任何只用于移动的模板,其中副本ctor内的static_assert等于编译错误,但为什么
- C2436 '{ctor}':构造函数初始值设定项列表中的成员函数或嵌套类
- 为什么在 ctor 的参数列表中将成员"x"的类型替换为"decltype(x)"会破坏类模板参数推导?
- 模板 ctor 类型推导不起作用(没有匹配的构造函数用于初始化 ...)与函数<>参数
- 为什么"non-standard syntax; use '&' to create a pointer to member"在 CTOR 中使用线程?
- 初始化在类类型 #define 中定义的非静态成员数组,不带默认 ctor
- 调用了Copy ctor而不是move ctor
- 使用 c'ctor、d'ctor 和 override