跳至主要內容

虚析构

张威大约 3 分钟c/c++多态

虚析构

虽然构造函数不能被定义成虚函数,但析构函数可以定义为虚函数,一般来说,如果类中定义了虚函数,析构函数也应被定义为虚析构函数,尤其是类内有申请的动态内存,需要清理和释放的时候。

什么时候需要把基类的析构函数必须实现成虚函数?

示例一:基类的指针(引用)指向的时候

基类的指针(引用)指向的时候,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关键字。