析构函数的 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。由于大多数现代编程语言都具有自动垃圾收集功能,因此不再需要显式调用析构函数。
希望对您有所帮助。
大多数关键的 OOP 概念都由析构函数显示。如果我们认为这些概念包括 Inheritance、Object、Class、封装, 方法, 消息传递, 多态性, 抽象、组合、委托和开放递归。然后我们可以展示所有这些通常在析构函数中发挥作用。
现在,通常"destructor" 表示在class 中定义的方法,当对象被销毁时自动调用*。这显然涵盖了 method、object 和 class.
析构函数封装了清理逻辑。考虑一个可以指向另一个结构的结构:
struct SomeStruct
{
SomeStruct* Next;
}
如果上面的代码是用不支持面向对象设计的语言编写的,让我们在 SomeStruct
本身上定义一个方法,并使用全局 delete()
方法删除堆对象,然后要清理 all SomeStruct 使用的内存,我们需要执行以下操作:
CleanUpSomeStruct(SomeStruct* toDelete)
{
while(toDelete != null)
{
SomeStruct* deleteNext = someStruct->Next;
delete(toDelete);
toDelete = deleteNext;
}
}
值得注意的是:
- 我们必须清理
SomeStruct
之外的 SomeStruct
。
- 没有什么可以阻止它被复制到其他地方。也许不正确。
- 我们必须能够直接访问
Next
,增加我们可能对其做出不明智行为的地方的数量。
- 如果我们遇到不应该删除
Next
的情况,那么虽然该知识可以存储在 SomeStruct
(可能是一个 ownsNext
字段)中,但执行操作的逻辑该知识是 SomeStruct
. 的外部知识
如果我们有析构函数那么:
struct SomeStruct
{
SomeStruct* Next;
~SomeStruct()
{
if(Next != null) delete(Next);
}
}
与上面对比:
- 清理
SomeStruct
的工作在 SomeStruct
中,靠近其他 SomeStruct
相关代码。
- 可以有一个访问控制的概念,它可以防止在其他地方被复制。
- 同样,访问控制可以阻止其他直接访问
Next
的情况,减少我们可能对其做出不明智行为的地方数量。
- 如果我们遇到不应该删除
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 的方法的使用都必须是确定性处置的一部分。
析构函数体现了哪个面向对象编程的概念?例如,重载显示多态性。请解释你的回答的原因。我在网上找不到这个..
释放程序资源的做法在 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。由于大多数现代编程语言都具有自动垃圾收集功能,因此不再需要显式调用析构函数。
希望对您有所帮助。
大多数关键的 OOP 概念都由析构函数显示。如果我们认为这些概念包括 Inheritance、Object、Class、封装, 方法, 消息传递, 多态性, 抽象、组合、委托和开放递归。然后我们可以展示所有这些通常在析构函数中发挥作用。
现在,通常"destructor" 表示在class 中定义的方法,当对象被销毁时自动调用*。这显然涵盖了 method、object 和 class.
析构函数封装了清理逻辑。考虑一个可以指向另一个结构的结构:
struct SomeStruct
{
SomeStruct* Next;
}
如果上面的代码是用不支持面向对象设计的语言编写的,让我们在 SomeStruct
本身上定义一个方法,并使用全局 delete()
方法删除堆对象,然后要清理 all SomeStruct 使用的内存,我们需要执行以下操作:
CleanUpSomeStruct(SomeStruct* toDelete)
{
while(toDelete != null)
{
SomeStruct* deleteNext = someStruct->Next;
delete(toDelete);
toDelete = deleteNext;
}
}
值得注意的是:
- 我们必须清理
SomeStruct
之外的SomeStruct
。 - 没有什么可以阻止它被复制到其他地方。也许不正确。
- 我们必须能够直接访问
Next
,增加我们可能对其做出不明智行为的地方的数量。 - 如果我们遇到不应该删除
Next
的情况,那么虽然该知识可以存储在SomeStruct
(可能是一个ownsNext
字段)中,但执行操作的逻辑该知识是SomeStruct
. 的外部知识
如果我们有析构函数那么:
struct SomeStruct
{
SomeStruct* Next;
~SomeStruct()
{
if(Next != null) delete(Next);
}
}
与上面对比:
- 清理
SomeStruct
的工作在SomeStruct
中,靠近其他SomeStruct
相关代码。 - 可以有一个访问控制的概念,它可以防止在其他地方被复制。
- 同样,访问控制可以阻止其他直接访问
Next
的情况,减少我们可能对其做出不明智行为的地方数量。 - 如果我们遇到不应该删除
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 的方法的使用都必须是确定性处置的一部分。