在c++中,多态使用时,如果子类中有属性开辟到了堆区,那么父类指针在释放时无法调用到子类的析构代码,解决方法就是将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构的共同点:1、都可以解决父类指针释放子类对象的问题 2、都需要具体的函数实现
虚析构和纯虚析构的区别:1、如果是纯虚析构,该类属于抽象类,无法实例化对象
下面为虚析构写法
class Anminal
{
public :
Anminal(){
cout<<"Anminal构造函数调用";
}
virtual ~Anminal() {
//这里父类析构写为虚析构,那么多态的时候就可以解决释放子类堆区数据问题
cout << "Anminal析构函数"
}
};
class Cat:public Anminal{
public:
Cat(string name){
n_name = new string(name);
//这里在堆区创建了属性,需要在Cat的析构函数中把这个属性释放
}
~Cat(){
if(n_name != NULL){
delete n_name;
n_name = NULL;
}
}
string * n_name;
};
void test(){
Animal * anminal = new Cat("xiao"); //多态的实现方法之一,使用父类指针指向子类对象
anminal->speak();
//因为这里是使用父类指针指向了子类的对象,所以在delete的时候不会调用子类中的析构函数
//所以需要将父类的析构函数写成虚析构或这纯虚析构函数,才会调用子类的析构函数
delete anminal;
}
下面为纯虚析构的写法
class Anminal
{
public :
Anminal(){
cout<<"Anminal构造函数调用";
}
virtual ~Anminal() = 0 ;
//这里父类析构写为纯虚析构,那么多态的时候就可以解决释放子类堆区数据问题
//有了纯虚析构之后,这个类变成了抽象类,无法实例化对象
};
Anminal:: ~Anminal(){ //纯虚析构也需要实现,这是和纯虚函数的区别,纯虚函数可以不实现
cout<<"Anminal纯虚析构函数";
}
class Cat:public Anminal{
public:
Cat(string name){
n_name = new string(name);
//这里在堆区创建了属性,需要在Cat的析构函数中把这个属性释放
}
~Cat(){
if(n_name != NULL){
delete n_name;
n_name = NULL;
}
}
string * n_name;
};
void test(){
Animal * anminal = new Cat("xiao"); //多态的实现方法之一,使用父类指针指向子类对象
anminal->speak();
//因为这里是使用父类指针指向了子类的对象,所以在delete的时候不会调用子类中的析构函数
//所以需要将父类的析构函数写成虚析构或这纯虚析构函数,才会调用子类的析构函数
delete anminal;
}
当然了,并不是所有情况都需要将父类析构写为虚析构和纯虚析构,只有在子类中一些属性创建在堆区,为了走子类中的析构代码,才需要将父类析构写为虚析构或纯虚析构。不论是虚析构还是纯虚析构都是为了解决子类中析构代码调不到的问题。