<五>关于虚析构函数
问题一:哪些函数不能实现成虚函数
虚函数依赖:
1:虚函数能产生地址,存储在vftable中
2:对象必须存储在 vfptr-> vftable-> 虚函数地址
**构造函数 **
1:virtual + 构造函数 (NO,不可以在构造函数前加virtual
2:构造函数中 调用的任何函数,都是静态绑定(lg:派生类对象构造过程中,先调用基类的构造函数,由于要通过对象拿到内存中的虚函数表指针,此时基类对象还没有构造出来,如何实现动态绑定?)
**static静态成员方法,也不可以加virtual,static静态成员方法的调用不基于对象 **
析构函数 可以 加 virtual,析构函数调用的时候,对象是存在的,所以可以通过对象内存拿到vfptr,进而找到vftable ,最后找到虚函数地址
问题二:虚析构函数,析构函数的调用的时候,对象是存在的
什么时候把基类的析构函数必须实现成虚函数?当 用基类的指针(引用)指向堆上new出来的派生类对象的时候
delete pb(pb是基类指针); 他调用析构函数的时候,必须发生动态绑定,否则会导致派生的析构函数无法调用,会有内存泄漏风险.
代码1
class Base
{
public:
Base(int data=10):ma(data){
cout<<"Base()"<<endl;
}
//虚函数
virtual void show(){cout<<"Base Show()"<<endl;}
//虚函数
virtual void show(int){cout<<"Base Show(int)"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
protected:
int ma;
};
class Derive : public Base
{
public:
Derive(int data=20):Base(data),mb(data){
cout<<"Derive()"<<endl;
}
void show(){cout<<"Derive Show()"<<endl;}
~Derive(){cout<<"~Derive()"<<endl;}
private:
int mb;
};
int main0(){
Derive d(20);
Base *pb=&d;
pb->show();
return 0;
//这个mian函数执行完成后执行顺序
//Base()构造函数->Derive()构造函数->~Derive()析构->~Base()析构 ,注意和下面的mian函数对比
}
int main1(){
Base *pb=new Derive d(20);
pb->show();
delete pb;
//这个main函数执行完成后执行顺序
//Base()构造函数->Derive()构造函数->~Base()析构
//发现 Derive的析构函数没有被调用,如果Derive中使用了外部资源,会有内存泄漏 ,注意和上面的mian函数对比
//pb是Base类型,所以去Base中看析构函数,发现是普通函数,所以执行编译期绑定,直接调用了Base的析构方法
//所以要将Base中的析构函数加上Virtual,当基类的析构方法是虚函数时,那么派生类的析构函数自动成为虚函数,发生动态绑定
//这是调用的是Derive的析构函数,在执行完Derive的析构函数后还会负责将基类的析构函数调用完成.
return 0;
}