虚析构与虚函数
1)当我们释放一个子类对象 delete derive;先调用子类析构函数,再调用父类析构函数
当我们释放一个指向子类的父类指针 base *p=new derive;delete p;若父类析构函数没有声明为虚函数,在delete p调用析构函数时,只会看指针的数据类型,而不会去看赋值的对象,这样就会造成内存泄露,即只执行父类的析构函数,不执行子类的析构函数;
因此当需要使用基类对派生类的对象操作时,如父类指针指向子类对象,需要将父类析构函数声明为虚,这样delete p时,先调用子类析构,再调用父类析构。
2)当我们调用一个子类对象的函数derive->func,则直接调用子类对象的func函数;
当我们通过父类指针指向子类对象调用函数 base *p=new derive;p->func,若func没有声明为虚,则只会看指针的数据类型,而不会去看赋值的对象,调用父类的func函数;
因此当需要使用基类对派生类的对象操作时,如父类指针指向子类对象,需要将父类函数声明为虚,这样调用函数时,调用的就是子类的func函数。
如果把子类析构想象成一个函数,其功能为先析构子类再析构父类,则上述1)2)完全一致
但是仍然存在不同之处:
#include <iostream>
#include <string>
using namespace std;
class A
{
public:
A()
{
cout << "a的构造" << endl;
}
virtual void func()
{
cout << "a的func" << endl;
func2();
}
virtual void func2()
{
cout << "a的func2" << endl;
}
virtual ~A()
{
cout << "a的析构" << endl;
func();
}
};
class B:public A
{
public:
B()
{
cout << "b的构造" << endl;
}
void func()
{
cout << "b的func" << endl;
func2();
}
void func2()
{
cout << "b的func2" << endl;
}
~B()
{
cout << "b的析构" << endl;
func();
}
};
int main(int argc, char* argv[])
{
A *p = new B;
cout << endl;
p->func();
cout << endl;
delete p;
return 0;
}
func为虚函数,p->func(),先调用B::func(),func2为虚函数,调用B::func2();
父类构造函数为虚,则delete p时,先调用子类析构:func为虚函数,先调用B::func(),func2为虚函数,调用B::func2()
再调用父类析构,func为虚函数,func2为虚函数,但子类已析构,调用A::func(),A::func2();
若将父类析构改为非虚,则输出为
此时子类析构函数没有执行,且父类析构中的虚函数都是其自身作用域下的函数。
若将func改为非虚,则输出为
可以看到,p->func执行的是父类的func,但其内的虚函数func2执行的仍是子类的func2。