为什么多态中父类要提供虚析构函数?
- 不提供虚析构函数
- 提供虚析构函数
如果说类与类之间产生了继承关系,并且在子类中重写了父类的虚函数,相当于最终要实现多态,就是用父类指针或引用指向子类的对象,并且通过父类指针调用子类里面重写父类的方法,这个子类对象被保存到父类的指针里面。当析构父类指针时,如果不提供父类的析构函数时,执行delete时,释放的是父类的对象,但是父类对象里面保存的是子类的地址,所以不能够完全析构掉子类对象。会造成内存泄露。
不提供虚析构函数
class A
{
public:
~A(){
cout<<"~A()"<<endl;
}
};
class B : public A
{
public:
~B(){
cout<<"~B()"<<endl;
}
};
int main()
{
B * pb = new B;
A * pa = pb;
delete pa;
return 0;
}
输出结果:
将子类的指针赋值给父类的指针,是可以的,称为赋值兼容,这也是形成多态的基础。
但在通过父类指针销毁子类对象时候,子类的析构器没有被调用。
因为父类的析构器不是虚函数,所以父类在调用析构时,调用的就是父类的构造器,所以子类的析构器没有被调用。
提供虚析构函数
class A
{
public:
virtual ~A(){
cout<<"~A()"<<endl;
}
};
class B : public A
{
public:
~B(){
cout<<"~B()"<<endl;
}
};
int main()
{
B * pb = new B;
A * pa = pb;
delete pa;
return 0;
}
**输出结果:
因为父类的析构函数是虚函数,且父类的指针指向了子类对象,所以父类在调用析构函数时,会调用子类的析构函数,编译器会在子类的析构函数中安插调用父类析构函数的代码,所以当子类对象的析构函数处理完后,父类的析构函数也会调用。这样一来,子类和父类的析构函数全都会被调用,析构完整。