为什么析构函数从派生调用到基类的最佳答案?

发布于 2024-12-09 12:41:27 字数 258 浏览 0 评论 0原文

我最近参加了一次采访,有人问我什么是建造和破坏的顺序。我解释说,建设是从基地到孩子,破坏是从孩子到基地。

采访者很想知道从派生到基地发生破坏是否有任何特殊原因。我向他解释了,但他不相信。

他的观点是,如果基类销毁给出异常,派生类如何知道派生类对象已经被销毁。

他还告诉我们,派生类包含基类成员,所以为什么我们不能先调用基类销毁呢?

我解释说,派生类销毁完成后,我们不能说对象已完全销毁。

我在这儿吗?这里最好的答案是什么?

I recently attended a interview where the person asked me what is order of construction and destruction. I explained that construction happened from base to child and destruction from child to base.

The interviewer was keen in knowing is there any special reason for destruction happening from derived to base. I explained him, but he was not convinced.

His point was what if base class destruction give exception, how would derived class know as derived class object would be already destructed.

He was also telling that derived class contains base class members so why can't we call base class destruction first?

I explained that after derived class destruction is done, we cannot say object is fully destructed.

Am i right here? what is the best answer here?

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

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

发布评论

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

评论(3

撩发小公举 2024-12-16 12:41:27

在 C# 中,对象构造遵循以下顺序:

  1. 数据成员的初始化 Derived -> 构造函数的基础
  2. 执行 Base ->衍生的。

为什么?

  • 初始化如下:Derived ->基以避免重新初始化在派生基中以不同方式初始化的成员。
  • 施工遵循基地 ->派生是因为派生构造函数可能依赖于基类的方法。

其他语言以不同的方式处理初始化,但 Base->派生结构是典型的。

销毁是从 Derived -> 进行的。根据。

为什么?

  • 派生体仍然可以使用依赖于销毁期间由基础分配的资源。

    • 如果基地首先被摧毁,这些资源将不再可供衍生者使用。
  • 层次结构的每个级别都应负责释放该级别分配的任何资源。

    • 基类无法释放派生类的资源,它对此一无所知。
    • 派生者也不应对基地分配的资源负责
      • 在严格的 OOP 中,派生者甚至不应该知道这些资源的详细信息,或者它们以何种方式分配或释放。

回应他的具体观点:

  • 基地的例外
    • 不应在析构函数中抛出异常(特别是在 C# 中,这至少有一次可能会杀死垃圾收集器)
  • 派生类包含基类成员
    • 该对象具有任一数据成员的一个实例。每一层继承权都没有一个。
      因此,我们回到如果基类释放与数据成员关联的资源,则派生类将不再可以使用该资源。

请您解释该命令的理由。如果我们假设 Derived->Base 顺序是正确的,这就解释了为什么您仍然必须调用 Base 析构函数,但不能解释为什么 Derived 首先出现。
如果有关顺序的关注点不同,并且销毁是在 Base->Derived 完成的,那么我们将能够在 Derived 析构函数完成后认为该对象已完全销毁,因为销毁将在所有级别上发生。

In C# Object construction follows this order:

  1. Initialization of data members Derived -> Base
  2. Execution of Constructors Base -> Derived.

Why?

  • Initialization follows Derived -> Base to avoid reinitialization of members initialized differently in the Derived from the base.
  • Construction follows Base -> Derived because the Derived constructor may rely on methods of the Base class.

Other languages handle the initialization differently, but the Base-> Derived construction is typical.

Destruction is done from Derived -> Base.

Why?

  • The Derived may still use rely on resources allocated by the Base during destruction.

    • If the Base were destroyed first, these resources would no longer be available for the Derived.
  • Each level of the heirarchy should be responsible for freeing up any resouces allocated by that level.

    • Base could not free the Derived Class's resources it has no knowledge of them.
    • Derived should also not be resposible for resources allocated by the Base
      • In strict OOP the derived shouldn't even know the details of those resources, or in what manner they are allocated or released.

To respond to his specific points:

  • Exception in the base
    • Exceptions should not be thrown in destructors (In Particular in C# this at least at one time could kill the garbage collector)
  • Derived classes contain Base class members
    • The object has one instance of any data member. Not one per level of heirarchy.
      So we return to if the base frees the resources associated with a data member, it will no longer be available for the Derived class to use.

To your explanation for the reasoning of the order. If we assume the Derived->Base order is correct, that explains why you must still call the Base destructor, but not why Derived comes first.
If the concerns regarding the order were different, and the destruction were completed Base->Derived then we would be able to consider the object completely destructed after the Derived destructor completed as destruction would have occurred on all levels.

十级心震 2024-12-16 12:41:27

你是绝对正确的。我曾经在面试经验丰富的 C++ 程序员时经常问这个问题。派生类必须在基类之后构造,以便派生类构造函数可以引用基类数据。出于同样的原因,派生类析构函数必须在基类析构函数之前运行。这是非常合乎逻辑的:我们从内到外构造,从外到内销毁。如果基类析构函数抛出异常,则派生类析构函数无法捕获该异常。基类构造函数中的异常也不能由派生类构造函数处理。一般来说,析构函数不应该抛出异常。

You are absolutely right. I used to ask this question frequently when interviewing experienced C++ programmers. The derived class must be constructed after the base class so that the derived class constructor can refer to base class data. For the same reason, the derived class destructor must run before the base class destructor. It's very logical: we construct from the inside out, and destroy from the outside in. If the base class destructor throws an exception, it cannot be caught by the derived class destructor. Nor can an exception in a base class constructor be handled by a derived class constructor. In general, exceptions should not be thrown from destructors.

≈。彩虹 2024-12-16 12:41:27

理解对象构造是分阶段进行的很重要。如果你有一个从 A 派生的类 B,则通过首先构造 A,然后将 A 转换为 B 来构造 B。同样,通过先将 B 转换为 A,然后销毁 A 来销毁 B。这提供了关于对象创建和销毁的非常一致的思考方式。

It is important to understand that object construction occurs in stages. If you have a class B derived from A, you construct B by first constructing an A and then turning the A into a B. Likewise, a B is destroyed by first turning it into an A, and then destroying the A. This provides a very consistent way of thinking about object creation and destruction.

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