析构函数的 OOP 概念?

OOP concept by destructors?

析构函数体现了哪个面向对象编程的概念?例如,重载显示多态性。请解释你的回答的原因。我在网上找不到这个..

释放程序资源的做法在 OOP 出现之前就存在了。即使在旧式 C 中,没有任何对象,您也必须相应地释放内存,否则会出现内存泄漏、资源锁定或其他不好的后果。

析构函数实现了我们所知的“Resource Acquisition Is Initialization

概念是垃圾收集。在 oop 中,您可以将它与释放之前分配给不再需要或删除的任何对象的 space 联系起来。

引用维基百科

In object-oriented programming, a destructor (sometimes shortened to dtor) is a method which is automatically invoked when the object is destroyed.

它的作用在清理方面很有用,例如释放程序不再使用的内存 space。由于大多数现代编程语言都具有自动垃圾收集功能,因此不再需要显式调用析构函数。

阅读有关 GC and Finalizer 的更多信息。

希望对您有所帮助。

大多数关键的 OOP 概念都由析构函数显示。如果我们认为这些概念包括 InheritanceObjectClass封装, 方法, 消息传递, 多态性, 抽象组合委托开放递归。然后我们可以展示所有这些通常在析构函数中发挥作用。

现在,通常"destructor" 表示在class 中定义的方法,当对象被销毁时自动调用*。这显然涵盖了 methodobjectclass.

析构函数封装了清理逻辑。考虑一个可以指向另一个结构的结构:

struct SomeStruct
{
   SomeStruct* Next;
}

如果上面的代码是用不支持面向对象设计的语言编写的,让我们在 SomeStruct 本身上定义一个方法,并使用全局 delete() 方法删除堆对象,然后要清理 all SomeStruct 使用的内存,我们需要执行以下操作:

CleanUpSomeStruct(SomeStruct* toDelete)
{
  while(toDelete != null)
  {
    SomeStruct* deleteNext = someStruct->Next;
    delete(toDelete);
    toDelete = deleteNext;
  }
}

值得注意的是:

  1. 我们必须清理 SomeStruct 之外的 SomeStruct
  2. 没有什么可以阻止它被复制到其他地方。也许不正确。
  3. 我们必须能够直接访问 Next,增加我们可能对其做出不明智行为的地方的数量。
  4. 如果我们遇到不应该删除 Next 的情况,那么虽然该知识可以存储在 SomeStruct(可能是一个 ownsNext 字段)中,但执行操作的逻辑该知识是 SomeStruct.
  5. 的外部知识

如果我们有析构函数那么:

struct SomeStruct
{
   SomeStruct* Next;
   ~SomeStruct()
   {
     if(Next != null) delete(Next);
   }
}

与上面对比:

  1. 清理 SomeStruct 的工作在 SomeStruct 中,靠近其他 SomeStruct 相关代码。
  2. 可以有一个访问控制的概念,它可以防止在其他地方被复制。
  3. 同样,访问控制可以阻止其他直接访问 Next 的情况,减少我们可能对其做出不明智行为的地方数量。
  4. 如果我们遇到不应该删除 Next 的情况,那么该逻辑可以存储在 SomeStruct 内部的一个地方。

另一方面,由于封装意味着我们可能无法访问 Next 封装意味着我们 具有能够清理的析构函数对象(或者给方法一个显式的 "Clean Yourself Up" 方法,但必须记住每次都调用它,并且知道它是否存在于给定的情况下,它被称为拖拽)。显然,如果我们有自动垃圾收集,这个例子就无关紧要,但在那些情况下,如果封装阻止外部代码执行必要的清理任务,我们同样需要某种析构函数。

同样,如果我们有继承,我们需要有可继承的析构函数,可以隐式或显式地传递清理任务:

struct SomeOtherStruct : SomeStruct
{
  SomeStruct* Prev;
  ~SomeOtherStruct()
  {
    if(Prev != null) delete(Prev);
    base.~SomeStruct(); // Possibly this would be implicit in that
                        // the language would automatically make a
                        // call to a destructor finish with a call
                        // to any base destructors.
  }
}

这也要求析构函数在一般意义上是抽象的,作为对象抽象模型的一部分(它可能与abstract 用于在其他上下文中强制抽象的关键字)。它们必须多态以便delete(Prev)调用Prev指向的对象中最派生的析构函数无论是~SomeStruct(),~SomeOtherStruct() 或另一个派生类型的析构函数,因此 Message Passing/Dynamic Dispatch 用于查找 abstract/virtual 析构函数的正确实现。 (一种语言可能会强制执行此操作,或者可能允许非虚拟析构函数作为优化)。

最后,析构函数与封装和开放递归交互,因为它们必须(可能隐含地)调用它们所组成的对象的析构函数,并且可能调用自身的方法来执行此操作。

*"when an object is destroyed" 对于 languages/frameworks 使用确定性对象删除比使用非确定性垃圾收集的对象更简单。通常在后一种情况下,"destructor" 指的是一种在非确定性收集最终发生时运行的方法(假设它曾经发生过),但如果它们有一个单独的 "disposal" 方法可以是确定性的,那么它可以服务确定性析构函数所起的一些作用。特别是,虽然确定性析构函数可用于提供 RAII 技术,但非确定性析构函数则不然,任何类似 RAII 的方法的使用都必须是确定性处置的一部分。