析构函数定义为虚函数场景(多态应用)
当对象生命周期结束时,每个析构函数只负责清理回收自己的资源。有时我们会遇到一个父类指针指向一个子类对象的情况,在撤销该指针时,编译器会实施静态绑定(编译时确定使用哪个函数),这样只会调用父类的析构函数而不调用子类析构函数,因而导致内存泄漏。为此,我们需要将析构函数定义为虚函数。
代码块1:
class CBase
{
public:
CBase()
{}
~CBase()
{
cout<<"~CBase()"<<endl;
}
void DoSomething()
{
cout<<"DoSomething in CBase"<<endl;
}
};
class CChild : public CBase
{
public:
CChild()
{}
~CChild()
{
cout<<"~CChild()"<<endl;
}
void DoSomething()
{
cout<<"DoSomething in CChild"<<endl;
}
};
void test1()
{
CChild *c=new CChild;
c->DoSomething();
delete c;
}
运行结果:
利用子类指针指向子类对象,在撤销子类指针时,先清理回收子类的资源,再清理回收父类资源。
代码块2:
class CBase
{
public:
CBase()
{}
~CBase()
{
cout<<"~CBase()"<<endl;
}
void DoSomething()
{
cout<<"DoSomething in CBase"<<endl;
}
};
class CChild : public CBase
{
public:
CChild()
{}
~CChild()
{
cout<<"~CChild()"<<endl;
}
void DoSomething()
{
cout<<"DoSomething in CChild"<<endl;
}
};
void test2()
{
CBase *c=new CChild;
c->DoSomething();
delete c;
}
运行结果:
利用父类指针指向子类对象,撤销父类指针时,由于编译器实施静态绑定,只清理回收父类对象,并没有清理回收子类对象,造成内存泄漏。
为了解决上述问题,需要将析构函数定义为虚函数(PS:父类希望其子类进行覆盖(重写)的函数也要变为虚函数),其实这也是C++中多态的基本实现。
代码块3(解决代码块2的问题):
class CBase
{
public:
CBase()
{}
virtual ~CBase()
{
cout<<"~CBase()"<<endl;
}
virtual void DoSomething()
{
cout<<"DoSomething in CBase"<<endl;
}
};
class CChild : public CBase
{
public:
CChild()
{}
~CChild()
{
cout<<"~CChild()"<<endl;
}
void DoSomething()
{
cout<<"DoSomething in CChild"<<endl;
}
};
void test2()
{
CBase *c=new CChild;
c->DoSomething();
delete c;
}
运行结果:
重要一点:
虚函数分析:当我们不需要用父类指针指向子类对象并操作时,则不可以去用virtual关键字定义虚函数,因为虚函数会增加系统内存开销。虚函数在底层实现时,编译器会给类增加一个虚函数表,虚函数表里面存放虚函数指针,如下图(基于代码块3):