【发布时间】:2015-09-19 14:24:27
【问题描述】:
析构函数显示了哪个面向对象编程概念?例如,重载显示多态性。请说明您回答的原因。我在网上的任何地方都找不到这个..
【问题讨论】:
标签: oop destructor
析构函数显示了哪个面向对象编程概念?例如,重载显示多态性。请说明您回答的原因。我在网上的任何地方都找不到这个..
【问题讨论】:
标签: oop destructor
大多数关键的 OOP 概念都由析构函数表示。如果我们认为这些概念包括继承、对象、类、封装、方法、消息传递、多态、抽象、组合、委托和打开递归。然后我们可以展示它们都在一般的析构函数中发挥作用。
现在,“析构函数”通常是指在类中定义的方法,该方法会在对象被销毁时自动调用*。这显然涵盖了方法、对象和类。
析构函数封装了清理逻辑。考虑一个可以指向另一个结构的结构:
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 封装意味着我们必须拥有能够清理对象的析构函数(或给方法一个明确的“清理自己”方法,但必须记住每次都调用它,并知道它是否存在于给定的情况下,以及它被称为拖累)。显然,如果我们有自动垃圾收集,这个例子就无关紧要了,但在那些情况下,如果封装阻止了外部代码进行必要的清理任务,我们同样需要某种析构函数。
同样,如果我们有继承,我们需要有可继承的析构函数,可以隐式或显式地将清理任务向上传递:
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 的方法都必须是确定性处置的一部分。
【讨论】:
释放程序资源的做法在 OOP 出现之前就已经存在。即使在老式 C 语言中,没有任何对象,您也必须相应地释放内存,否则会出现内存泄漏、资源锁定或其他不好的后果。
【讨论】:
析构函数实现了我们所知的“Resource Acquisition Is Initialization”
【讨论】: