先来看几段程序例子:
1. 将基类析构函数声明为虚函数
#include <iostream>
using namespace std;
class Person{
public:
virtual ~Person(){ //declare destructor as a virtual function
cout <<"Person::~Person()" << endl;
}
};
class Student : public Person{
public:
~Student(){ // virtual or not is OK
cout<< "Student::~Student()" << endl;
}
};
int main(){
Person *pt1 = new Person;
Person *pt2 = new Student; // base class pointer point to derived class
// Student *pt3 =new Person; // derived class pointer can not point tobase class
Student *pt4 = new Student;
delete pt1;
cout <<"*********" << endl;
delete pt2;
cout <<"*********" << endl;
//delete pt3;
//cout <<"*********" << endl;
delete pt4;
cout <<"*********" << endl;
return 0;
}
运行结果:
2.不将基类析构函数声明为虚函数:
#include <iostream>
using namespace std;
class Person{
public:
~Person(){ //declare destructor as a virtual function
cout <<"Person::~Person()" << endl;
}
};
class Student : public Person{
public:
~Student(){ // virtual or not is OK
cout<< "Student::~Student()" << endl;
}
};
int main(){
Person *pt1 = new Person;
Person *pt2 = new Student; // base class pointer point to derived class
// Student *pt3 =new Person; // derived class pointer can not point tobase class
Student *pt4 = new Student;
delete pt1;
cout <<"*********" << endl;
delete pt2;
cout <<"*********" << endl;
//delete pt3;
//cout <<"*********" << endl;
delete pt4;
cout <<"*********" << endl;
return 0;
}
运行结果:
可以看出:
在用基类指针指向派生类时,
在基类析构函数声明为virtual的时候,delete基类指针,会先调用派生类的析构函数,再调用基类的析构函数。
在基类析构函数没有声明为virtual的时候,delete基类指针,只会调用基类的析构函数,而不会调用派生类的析构函数,这样会造成销毁对象的不完全。
分析:
Person *pt2 = new Student;
pt2的静态类型为Person,而动态类型为Student,
当析构函数为虚函数时,为动态绑定,delete pt2,会调用动态类型即派生类的析构函数,由于继承关系,也会调用基类的析构函数;
而当析构函数为非虚函数时,为静态绑定,delete pt2,会调用静态类型即基类的析构函数,而不会调用派生类的析构函数。
3.总结:
警告: deletingobject of polymorphic class type which has non_virtual destructor might causeundefine behavior
原来如果基类里有虚函数,定义了基类指针指向派生类,就会需要定义基类虚析构,这样,基类指针析构的时候,就会先析构派生类,再析构基类。
如果不定义虚析构,就会基类指针直接析构基类。这样派生类对象销毁不完整。所以编译器会告诉你,警告你的。
在代码设计的时候,如果派生类有自己在heap中申请的空间,而且会用到派生类向基类的转化,那么一定要声明虚析构函数。若果没有同时满足上述两个条件, 则不要声明虚析构函数(申明虚析构函数和申明虚成员函数一样,都会占用一个virtualpointer)。
在代码设计的过程中,最好是显式的同时声明基类和派生类的析构函数为虚函数。
确保使用使用指向派生类对象的基类指针释放派生类对象的内存空间时,
派生类的析构函数可以正常的调用。就是所谓的多态吧
如果你用基类的指针指向一个派生类对象。再删除这个对象的时候,只会执行基类的析构函数而不会执行派生类的析构。只有把基类的析构设为虚函数的时候才会执行派生类的析构。
如果需要从基类来删除对象的话,对象的析构函数需要为virtual 。