每个类都应该有一个虚拟析构函数吗?

发布于 2024-07-09 16:53:25 字数 745 浏览 12 评论 0原文

Java 和 C# 支持类的概念,但不能使用 finalsealed 关键字用作基类。 然而,在 C++ 中,没有好的方法来阻止派生类,这让类的作者陷入了两难境地:每个类是否都应该有一个虚拟析构函数?


编辑:自 C++11 起不再如此,您可以指定类为 最终


一方面,为对象提供虚拟析构函数意味着它将拥有一个 vtable,因此每个对象会为 vptr 消耗 4 个(或 64 位计算机上的 8 个)额外字节。

另一方面,如果后来有人从此类派生并通过指向基类的指针删除派生类,则程序将定义不明确(由于缺少虚拟析构函数),坦率地说,针对每个对象的指针进行优化是荒谬的。

紧握的手上,有一个虚拟析构函数(可以说)广告该类型旨在以多态方式使用。

有些人认为你需要一个明确的理由来不使用虚拟析构函数(正如这个问题的潜台词),而其他人则说你仅当您有理由相信您的类是派生自的时才应该使用它们,认为什么?

Java and C# support the notion of classes that can't be used as base classes with the final and sealed keywords. In C++ however there is no good way to prevent a class from being derived from which leaves the class's author with a dilemma, should every class have a virtual destructor or not?


Edit: Since C++11 this is no longer true, you can specify that a class is final.


On the one hand giving an object a virtual destructor means it will have a vtable and therefore consume 4 (or 8 on 64 bit machines) additional bytes per-object for the vptr.

On the other hand if someone later derives from this class and deletes a derived class via a pointer to the base class the program will be ill-defined (due to the absence of a virtual destructor), and frankly optimizing for a pointer per object is ridiculous.

On the gripping hand having a virtual destructor (arguably) advertises that this type is meant to be used polymorphically.

Some people think you need an explicit reason to not use a virtual destructor (as is the subtext of this question) and others say that you should use them only when you have reason to believe that your class is to be derived from, what do you think?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

じее 2024-07-16 16:53:25

每个抽象类都应该有一个

  • 受保护的析构函数或
  • 虚拟析构函数。

如果您有一个公共非虚拟析构函数,那就不好了,因为它允许用户通过该指针删除派生对象。 因为众所周知,这是未定义的行为。

对于抽象类,您已经需要对象中的虚拟表指针,因此使析构函数虚拟化(据我所知)不会在空间或空间方面产生很高的成本运行时性能。 它的好处是派生类自动拥有其析构函数virtual(请参阅@Aconcagua 的评论)。 当然,对于这种情况,您也可以将析构函数设为protected virtual

对于不打算通过指向它的指针删除的非抽象类,我认为没有充分的理由使用虚拟析构函数。 这样会浪费资源,更重要的是会给用户带来错误的提示。 想想看,给 std::iterator 一个虚拟析构函数会有什么奇怪的意义。

Every abstract class should either have a,

  • protected destructor, or,
  • virtual destructor.

If you've got a public non-virtual destructor, that's no good, since it allows users to delete through that pointer a derived object. Since as we all know, that's undefined behavior.

For an abstract class, you already need a virtual-table pointer in the object, so making the destructor virtual doesn't (as far as I'm aware) have a high cost in terms of space or runtime performance. And it has the benefit that derived classes automatically have their destructors virtual (see @Aconcagua's comment). Of course, you can also make the destructor protected virtual for this case.

For a non-abstract class not intended to be deleted through a pointer to it, I don't think there's good reason to have a virtual destructor. It would waste resources, but more importantly it would give users a wrong hint. Just think about what weird sense it would make to give std::iterator a virtual destructor.

鸢与 2024-07-16 16:53:25

问题实际上是,您是否想要强制关于如何使用您的类的规则? 为什么?
如果一个类没有虚拟析构函数,则使用该类的任何人都知道该类不打算派生自该类,并且如果您尝试使用该类,则会受到哪些限制。 这还不够好吗?

或者,如果有人敢于做一些你没有预料到的事情,你是否需要编译器抛出一个硬错误?

如果您打算让人们从类中派生,请为该类提供一个虚拟析构函数。 否则,不要这样做,并假设使用您的代码的任何人都足够聪明,可以正确使用您的代码。

The question is really, do you want to enforce rules about how your classes should be used? Why?
If a class doesn't have a virtual destructor, anyone using the class knows that it is not intended to be derived from, and what limitations apply if you try it anyway. Isn't that good enough?

Or do you need the compiler to throw a hard error if anyone dares to do something you hadn't anticipated?

Give the class a virtual destructor if you intend for people to derive from it. Otherwise don't, and assume that anyone using your code is intelligent enough to use your code correctly.

暗恋未遂 2024-07-16 16:53:25

不! 仅当通过基类指针删除派生类的对象时,才使用虚拟析构函数。 如果您的类不打算作为这种情况下的基础,请不要将析构函数设为虚拟 - 您将发送错误的消息。

No! Virtual destructors are used only when a object of a derived class is deleted through a base class pointer. If your class is not intended to serve as the base in this scenario, don't make the destructor virtual - you would be sending a wrong message.

陪你搞怪i 2024-07-16 16:53:25

查看 Herb Sutter 的这篇文章

指南 #4:基类析构函数应该是 public和虚拟的,或受保护的和非虚拟的。

Check this article from Herb Sutter:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

意中人 2024-07-16 16:53:25

对于一般性问题,我会说“不”。 并非每个类都需要一个。 如果您知道该类永远不应该被继承,那么就不需要承担较小的开销。 但如果有机会,为了安全起见,还是放一个进去吧。

I would "no" to the general question. Not every class needs one. If you can know that the class should never be inherited from, then there is no need to incur the minor overhead. But if there is a chance, be on the safe side and put one in there.

早茶月光 2024-07-16 16:53:25

当基类至少包含一个纯虚函数时,它就成为抽象类。 如果 Base 没有虚拟析构函数,而 Derived(从 Base 派生)有,则可以通过 Derived 对象指针而不是通过 Base 对象指针安全地销毁 Derived 对象。

Base class becomes abstract class, when it contains at least one pure virtual function. If Base does not have a virtual destructor and Derived (derived from Base) does, then you can safely destroy a Derived object through a Derived object pointer but not through a Base object pointer.

贱贱哒 2024-07-16 16:53:25

我要补充的是,有时当我忘记父类或子类中的虚拟时,我会因为析构函数没有被调用而苦恼一段时间。 我想我现在知道要寻找那个了。 :)

有人可能会争辩说,有时父类在其析构函数中做了一些子类不应该做的事情......但这可能表明您的继承结构出现了问题。

I'll add that there have been times when I have scratched my head for a while on destructors not getting called when I forgot a virtual in the parent or child class. I guess I know to look for that now though. :)

Someone might argue that there are times the parent class does something in its destructor that a child should not do... but that's probably an indicator of something wrong with your inheritance structure anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文