为什么要用“虚析构函数”?

 析构函数的工作方式是:

      最底层的派生类(most   derived   class)的析构函数最先被调用,然后调用每一个基类的析构函数。

      因为在C++中,当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较有代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这就导致了一个古怪的“部分析构”对象,这是一个泄漏资源。排除这个问题非常简单:给基类一个虚析构函数。于是,删除一个派生类对象的时候就有了你所期望的正确行为。将销毁整个对象,包括全部的派生类部分。

      但是,一般如果不做基类的类的析构函数一般不声明为虚函数,因为虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为   vptr(virtual   table   pointer,虚函数表指针)的指针的形式。vptr   指向一个被称为   vtbl(virtual   table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到   vtbl。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的   vptr   指向的   vtbl,然后在   vtbl   中寻找合适的函数指针。这样子会使类所占用的内存增加

 

虚析构函数  
      析构函数也可以是虚的,甚至是纯虚的。例如:  

class   A  

{  

public:  

    virtual   ~A()=0;   //   纯虚析构函数  

};  

 

当一个类打算被用作其它类的基类时,它的析构函数必须是虚的。考虑下面的例子:  

class   A  

{  

public:  

    A()  

    {  

        ptra_   =   new   char[10];

    }  

    ~A()  

    {  

        delete[]   ptra_;

    } //   非虚析构函数  

private:  

    char   *   ptra_;  

};  

 

class   B:   public   A  

 {  

public:  

    B()  

    {  

        ptrb_   =   new   char[20];

    }  

    ~B()  

    {  

        delete[]   ptrb_;

    }  

private:  

    char   *   ptrb_;  

};  

void   foo()  

{  

    A   *   a   =   new   B;  

    delete   a;  

}  

 

在这个例子中,程序也许不会象你想象的那样运行,在执行delete   a的时候,实际上只有A::~A()被调用了,而B类的析构函数并没有被调用!这是否有点儿可怕?如果将上面A::~A()改为virtual,就可以保证B::~B()也在delete   a的时候被调用了。因此基类的析构函数都必须是virtual的。纯虚的析构函数并没有什么作用,是虚的就够了。通常只有在希望将一个类变成抽象类(不能实例化的类),而这个类又没有合适的函数可以被纯虚化的时候,可以使用纯虚的析构函数来达到目的。

阅读更多
个人分类: C++
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

为什么要用“虚析构函数”?

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭