C++虚析构函数主要关注两个问题,何时要用虚析构以及它是怎么工做的。下面回答这两个问题。ios
答案:经过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。这样作是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。c++
缘由:用对象指针来调用一个函数,有如下两种状况:若是是虚函数,会调用派生类中的版本; 若是是非虚函数,会调用指针所指类型的实现版本。 析构函数也会遵循以上两种状况。当对象出了做用域或是咱们删除对象指针,析构函数就会被调用。当派生类对象出了做用域,派生类的析构函数会先调用,而后再调用它父类的析构函数,这样能保证分配给对象的内存获得正确释放。可是,若是咱们删除一个指向派生类对象的基类指针,而基类析构函数又是非虚的话, 那么就会先调用基类的析构函数(上面第2种状况),派生类的析构函数得不到调用。这样会形成销毁对象不彻底。bash
简要解释就是:析构函数执行时先调用派生类的析构函数,其次才调用基类的析构函数。若是析构函数不是虚函数,而程序执行时又要经过基类的指针去销毁派生类的动态对象,那么用delete销毁对象时,只调用了基类的析构函数,未调用派生类的析构函数。这样会形成销毁对象不彻底。函数
注意:并非要把全部类的析构函数都写成虚函数。由于当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增长类的存储空间。因此,只有当一个类被用来做为基类的时候,才把析构函数写成虚函数。ui
代码实例以下:this
class Base{
public:
Base() { cout<<"Base Constructor"<<endl; }
// ~Base() { cout<<"Base Destructor"<<endl; }
virtual ~Base() { cout<<"Base Destructor"<<endl; }
};
class Derived: public Base{
public:
Derived() { cout<<"Derived Constructor"<<endl; }
~Derived() { cout<<"Derived Destructor"<<endl; }
};
int main(){
Base *p = new Derived();
delete p;
return 0;
}
复制代码
未添加虚析构函数输出:spa
BaseConstructor
DerivedConstructor
BaseDestructor
复制代码
添加虚析构函数输出:指针
BaseConstructor
DerivedConstructor
DerivedDestructor
BaseDestructor
复制代码
虚函数依赖虚函数表进行工做。若是一个类中,有函数被关键词virtual进行修饰, 那么一个虚函数表就会被构建起来保存这个类中虚函数的地址。同时,编译器会为这个类添加一个隐藏指针(虚函数表的指针)指向虚函数表。若是在派生类中没有重写虚函数,那么,派生类中虚表存储的是父类虚函数的地址。每当虚函数被调用时, 虚表会决定具体去调用哪一个函数。所以,C++中的动态绑定是经过虚函数表机制进行的。当咱们用基类指针指向派生类时,虚表指针vptr指向派生类的虚函数表。 这个机制能够保证派生类中的虚函数被调用到。code
示例代码:对象
#include <iostream>
using namespace std;
class Shape{
public:
Shape(){}
Shape(int edge_length){
this->edge_length = edge_length;
}
virtual ~Shape(){
cout<<"Shape destructure."<<endl;
}
virtual int circumstance(){
cout<<"circumstance of base class."<<endl;
return 0;
}
protected:
int edge_length;
};
class Triangle: public Shape{
public:
Triangle(){}
Triangle(int edge_length){
this->edge_length = edge_length;
}
~Triangle(){
cout<<"Triangle destructure."<<endl;
}
int circumstance(){
cout<<"circumstance of child class."<<endl;
return 3 * this->edge_length;
}
};
int main() {
Shape *x = new Shape();
x->circumstance();
Shape *y = new Triangle(10);
int num = y->circumstance();
cout<<num<<endl;
delete x;
delete y;
return 0;
}
复制代码
运行结果:
circumstance of base class.
circumstance of child class.
30
Shape destructure.
Triangle destructure.
Shape destructure.
复制代码