虚析构
大约 3 分钟
虚析构
虽然构造函数不能被定义成虚函数,但析构函数可以定义为虚函数,一般来说,如果类中定义了虚函数,析构函数也应被定义为虚析构函数,尤其是类内有申请的动态内存,需要清理和释放的时候。
什么时候需要把基类的析构函数必须实现成虚函数?
示例一:基类的指针(引用)指向的时候
基类的指针(引用)指向的时候,delete调用析构函数的时候,必须发生动态绑定,否则会导致派生类的析构函数无法调用。
class Base
{
public:
Base(int data) :ma(data)
{
cout << "Base()" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
virtual void show()
{
cout << "call Base::show()" << endl;
}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data):Base(data), mb(data),ptr(new int(data))
{
cout << "Derive()" << endl;
}
~Derive()
{
delete ptr;
cout << "~Derive() " << endl;
}
private:
int mb;
int *ptr;
};
int main()
{
Base *pb = new Derive(10);
pb->show();//动态绑定pb Base* *pb Derive
delete pb;
return 0;
}
执行出现问题:。

pb的类型是Base类型,因此delete调用析构函数先去Base中找Base::~Base(),此时对于析构函数的调用就是,没有机会调用派生类的析构函数,最后发生内存泄露。
解决方案: 将基类的析构函数定义为虚析构函数,派生类的析构函数自动成为虚函数。 pb的类型是Base类型,调用析构时去Base中找Base::~Base
发现它为虚函数,发生动态绑定。派生类的虚函数表中:&Derive:: ~derive
,用派生类析构函数将自己部分进行析构,再调用基类的析构函数将基类部分析构。
class Base
{
public:
Base(int data) :ma(data)
{
cout << "Base()" << endl;
}
virtual~Base()
{
cout << "~Base()" << endl;
}
virtual void show()
{
cout << "call Base::show()" << endl;
}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data):Base(data), mb(data),ptr(new int(data))
{
cout << "Derive()" << endl;
}
~Derive()
{
delete ptr;
cout << "~Derive() " << endl;
}
private:
int mb;
int *ptr;
};

示例二:类内有申请的,需要清理和释放的时候
class Base
{
public:
Base(const char *pbase)
: _pbase(new char[strlen(pbase) + 1]())
{
cout << "Base(const char *)" << endl;
strcpy(_pbase, pbase);
}
/*virtual*/
~Base()
{
if(_pbase)
{
delete [] _pbase;
_pbase = nullptr;
}
cout << "~Base()" << endl;
}
private:
char *_pbase;
};
class Derived
: public Base
{
public:
Derived(const char *pbase, const char *pderived)
: Base(pbase)
, _pderived(new char[strlen(pderived) + 1]())
{
cout << "Derived(const char *, const char *)" << endl;
strcpy(_pderived, pderived);
}
~Derived()
{
cout << "~Derived()" << endl;
if(_pderived)
{
delete [] _pderived;
_pderived = nullptr;
}
}
private:
char *_pderived;
};
void test()
{
Base *pbase = new Derived("hello", "wuhan");
pbase->print();
delete pbase;
}
如果基类Base的析构函数没有设置为虚函数, 则在执行delete pbase;
语句时,不会调用派生类Derived的析构函数,这样就会造成。此时,将基类Base的析构函数设置为虚函数,就可以解决该问题。
如果基类的析构函数声明为虚的,派生类的析构函数也将自动成为虚析构函数,无论派生类析构函数声明中是否加virtual关键字。