如何虚拟析构函数在C ++中工作 [英] How Does Virtual Destructor work in C++

查看:129
本文介绍了如何虚拟析构函数在C ++中工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将输入一个例子:

class A
{
public:
virtual ~A(){}
};

class B: public A
{
public:
~B()
{
}

};



int main(void)
{
A * a =  new B;
delete a;
return 0;
}

现在在上面的例子中,析构函数将被递归调用。
我的问题是编译器如何做这个MAGIC。

Now in Above Example , destructors will be called recursively bottom to up . My Question is how Compiler do this MAGIC .

推荐答案

em>在您的问题。第一个是编译器如何为析构函数调用最终的overrider,第二个是如何按顺序调用所有其他的析构函数。

There are two different pieces of magic in your question. The first one is how does the compiler call the final overrider for the destructor and the second one is how does it then call all the other destructors in order.

免责声明:标准不要求执行此操作的任何特定方式,它仅强制在较高级别的操作的行为。

Disclaimer: The standard does not mandate any particular way of performing this operations, it only mandates what the behavior of the operations at a higher level are. These are implementation details that are common to various implementations, but not mandated by the standard.

编译器如何调度到最终的overrider?

第一个答案是简单的,使用用于其他 virtual 函数的相同动态调度机制用于析构函数。为了刷新它,每个对象都为它的每个 vtable 存储一个指针( vptr 继承可以有多个),当编译器看到对任何虚函数的调用时,它遵循指针的静态类型的 vptr ,以找到 vtable ,然后使用该表中的指针转发调用。在大多数情况下,调用可以直接调度,在其他(多重继承)调用一些中间代码( thunk ),修复 this

The first answer is the simple one, the same dynamic dispatch mechanism that is used for other virtual functions is used for destructors. To refresh it, each object stores a pointer (vptr) to each of its vtables (in the event of multiple inheritance there can be more than one), when the compiler sees a call to any virtual function, it follows the vptr of the static type of the pointer to find the vtable and then uses the pointer in that table to forward the call. In most cases the call can be directly dispatched, in others (multiple inheritance) it calls some intermediate code (thunk) that fixes the this pointer to refer to the type of the final overrider for that function.

那么编译器如何调用基本析构函数?

破坏对象的过程所需的操作比那些在析构函数体内写的操作更多。当编译器生成析构函数的代码时,它会在用户定义的代码之前和之后添加额外的代码。

The process of destructing an object takes more operations than those you write inside the body of the destructor. When the compiler generates the code for the destructor, it adds extra code both before and after the user defined code.

在调用用户定义析构函数的第一行之前,编译器会注入使得对象类型为调用析构函数类型的代码。也就是说,在输入〜derived 之前,编译器添加将修改 vptr 的代码, code> 的 c>,使得对象的运行时类型有效地 derived (*)

Before the first line of a user defined destructor is called, the compiler injects code that will make the type of the object be that of the destructor being called. That is, right before ~derived is entered, the compiler adds code that will modify the vptr to refer to the vtable of derived, so that effectively, the runtime type of the object becomes derived (*).

在用户定义的代码的最后一行之后,调用成员析构函数以及基本析构函数。这是通过禁用动态分派来执行的,这意味着它将不再完全落到刚刚执行的析构函数。它相当于在析构函数的末尾添加 this->〜mybase(); 用于对象的每个基础(以相反的碱基声明顺序) 。

After the last line of your user defined code, the compiler injects calls to the member destructors as well as base destructor(s). This is performed disabling dynamic dispatch, which means that it will no longer come all the way down to the just executed destructor. It is the equivalent of adding this->~mybase(); for each base of the object (in reverse order of declaration of the bases) at the end of the destructor.

通过虚拟继承,事情变得更加复杂,但总体上它们遵循这种模式。

With virtual inheritance, things get a bit more complex, but overall they follow this pattern.


当直接或间接从构造函数(包括从数据成员的mem-initializer)或从析构函数中调用虚函数时,调用应用的是正在构造或销毁的对象,调用的函数是在构造函数或析构函数自己的类中或在其中一个基础中定义的函数,但不是一个函数覆盖从构造函数或析构函数类或者在最导出对象的其他基类中重写它。

When a virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from a destructor, and the object to which the call applies is the object under construction or destruction, the function called is the one defined in the constructor or destructor’s own class or in one of its bases, but not a function overriding it in a class derived from the con- structor or destructor’s class, or overriding it in one of the other base classes of the most derived object.

这个要求意味着对象是在此时被构造/破坏的类的,即使被构造/破坏的原始对象是派生类型。验证此实现的简单测试可以是:

That requirement implies that the runtime type of the object is that of the class being constructed/destructed at this time, even if the original object that is being constructed/destructed is of a derived type. A simple test to verify this implementation can be:

struct base {
   virtual ~base() { f(); }
   virtual void f() { std::cout << "base"; }
};
struct derived : base {
   void f() { std::cout << "derived"; }
};
int main() {
   base * p = new derived;
   delete p;
}

这篇关于如何虚拟析构函数在C ++中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆