虚拟类的析构函数究竟做了什么?

时间:2014-03-14 16:59:28

标签: c++ inheritance constructor destructor

假设我们有课程。

class A 
{
public:

   void doSomething() = 0;
   A();
   virtual ~A();

private:

   vector<SomeStuff> cont;
   bool yesNo;

}

class B: public A
{

public:

   B();
   ~B();

private:

   bool Byesno;
}

因此首先调用A的构造函数,然后在此之后调用B的构造函数,当我们销毁B时,首先调用B的析构函数,然后调用A的析构函数。所以基本上,A的析构函数将删除B的继承变量,B的析构函数将删除其特定于类的析构函数。我是对的吗?

我不明白的是,如果我们甚至无法实例化A类型的对象,我们怎么能调用A的析构函数?它在内部如何运作?

2 个答案:

答案 0 :(得分:2)

B是A等等。将调用A的析构函数以确保清除B的一部分。你的类不使用虚拟关键字,所以我不确定你为什么想知道虚拟析构函数,但是因为你想知道这可能会有所帮助:

class A
{
   public:
       virtual ~A() { cout << "A::~A()" << endl; }
};

class B : public A
{
   public:
       ~B() { cout << "B::~B()" << endl; }
};

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

您期望的输出将是

B::~B()
A::~A()

但是,如果你没有声明A的析构函数是虚拟的,那么输出就是

A::~A()

因此,总之,如果您的代码涉及多态,并且您希望调用指向对象的析构函数而不是指针类型本身的析构函数,则必须将基类析构函数声明为虚拟。

答案 1 :(得分:1)

每个析构函数都经历了三个阶段:

  1. 用户代码
  2. 将类成员的破坏委托给相应的析构函数
  3. 将基类的销毁委托给相应的析构函数
  4. 原始类型的析构函数通常是微不足道的,即什么都不做。从技术上讲,你可以想到

    B::~B() { Byesno = false; }
    

    作为

    B::~B()
    {
        Byesno = false;  // explicit
        Byesno.~bool();  // implicit, member
        A::~A();         // implicit, base class
    }
    
    
    A::~A()
    {
        yesNo.~bool();   // implicit, member
        cont.~vector();  // implicit, member
    }
    

    ~bool()为空且会被内联,因此您可以看到的唯一一个是~vector()的电话。

    这一切都是一个独立的问题。如果A's d'tor是非虚拟的,只有当被破坏的对象被认为是B对象时才会调用B's'tor':

    A a;
    B b;
    A *ap = new B;
    delete ap;
    

    这将~A()对象使用a(正确),~B()对象使用b(也正确),对象使用~A()ap指出(不正确,但我们不知道更好)。如果~A()是虚拟的,则会在v'table中查找d'tor调用本身,其中包含指向~B()的指针。

    a tiny bit more complex than that,但不多。