【问题标题】:OOP concept by destructors?析构函数的OOP概念?
【发布时间】:2015-09-19 14:24:27
【问题描述】:

析构函数显示了哪个面向对象编程概念?例如,重载显示多态性。请说明您回答的原因。我在网上的任何地方都找不到这个..

【问题讨论】:

    标签: oop destructor


    【解决方案1】:

    大多数关键的 OOP 概念都由析构函数表示。如果我们认为这些概念包括继承对象封装方法消息传递多态抽象组合委托打开递归。然后我们可以展示它们都在一般的析构函数中发挥作用。

    现在,“析构函数”通常是指在类中定义的方法,该方法会在对象被销毁时自动调用*。这显然涵盖了方法对象

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

    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 之外.

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

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

    与上述相反:

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

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

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

    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 在一般意义上的对象抽象模型的一部分(它可能与用于强制执行的 abstract 关键字无关其他情况下的抽象)。它们必须是多态的,以便delete(Prev) 调用Prev 指向的对象中最派生的析构函数,无论它是~SomeStruct()~SomeOtherStruct() 还是另一个派生类型的析构函数,所以消息传递/动态分派用于找到抽象/虚拟析构函数的正确实现。 (一种语言可以强制执行这一点,或者可以允许非虚拟析构函数作为优化)。

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

    *“当一个对象被销毁时”对于使用确定性删除对象的语言/框架来说是一个比使用非确定性垃圾收集的语言/框架更简单的概念。通常在后一种情况下,“析构函数”是指在最终发生非确定性收集时运行的方法(假设它曾经发生过),但如果它们有一个单独的可以是确定性的“处置”方法,那么它可能会起到一些作用确定性析构函数服务。特别是,虽然确定性析构函数可用于提供 RAII 技术,但非确定性析构函数没有,任何使用类似 RAII 的方法都必须是确定性处置的一部分。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        引用维基百科

        在面向对象编程中,析构函数(有时缩写为 dtor) 是一个在对象被调用时自动调用的方法 销毁。

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

        阅读GCFinalizer 了解更多信息。

        希望对你有帮助。

        【讨论】:

          【解决方案4】:

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

          【讨论】:

          • 如果销毁是确定性的,那么它可以用于实现 RAII(如果有的话,它应该被称为 Resource Release Is Destruction)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多