看题,读代码写结果
#include <stdio.h>
class CPerson{
public:
virtual void Whoami() = 0;
};
class CStudent : public CPerson{
public:
CStudent(){printf("student is created!\r\n");}
virtual ~CStudent(){printf("student is destroy!\r\n");}
virtual void Whoami(){printf("student!\r\n");}
};
class CTeacher : public CPerson{
public:
CTeacher(){printf("teacher is created!\r\n");}
virtual ~CTeacher(){printf("teacher is destroy!\r\n");}
virtual void Whoami(){printf("teacher!\r\n");}
};
int main(){
CPerson *pLily = new CTeacher();
pLily->Whoami();
delete (CTeacher *)pLily;
CPerson *pLucy = new CStudent();
pLucy->Whoami();
delete pLucy;
return 0;
}
**思考写写看你的答案~**
1.先了解虚函数以及虚析构函数的作用:
虚函数的作用
在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。
虚析构函数的作用
目的是基类的指针指向派生类对象,并用基类的指针删除派生类对象
2.再来了解一下构造函数和析构函数的作用顺序:
构造函数和析构函数的顺序就像盖房子和拆房子,最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。
盖房子
1、基类构造函数执行。
2、派生类构造函数执行。
拆房子
3、派生类析构函数执行。
4、基类析构函数执行。
3.为什么要声明虚析构函数
基类指针可以指向派生类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样就会造成派生类对象析构不完全。所以,为了避免内存泄露,将析构函数声明为虚函数是十分必要的。
4.再来看一道题的答案
结果显而易见
5.分析代码
int main()
{
CPerson *pLily = new CTeacher();
//基类指针指向派生类 new 调用CTeacher类构造函数 打印teacher is created!*
pLily->Whoami();
//调用CTeacher类的whoami成员函数 打印teacher!
delete (CTeacher *)pLily;
//强制类型转换为Cteacher类指针 调用Cteacher类析构函数和抽象基类默认析构函数 打印 //teacher is destroy!
CPerson *pLucy = new CStudent();
pLucy->Whoami();
delete pLucy; //调用抽象基类默认析构函数,无打印内容
return 0;
}
6.总结学习
从这里我们可以注意到,为了防止内存泄漏,即先析构派生类后析构基类,完成完全释放内存,可以通过:
①:虚化父类析构
即当基类指针可以指向派生类的对象,删除该指针delete []p,就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。
②:强转指针Delete
即将其强转为子类的指针再进行delete,则会先走子类析构,再走父类析构。
#创作不易,有什么不理解或者有什么错误的地方,欢迎一起交流 | |
---|---|