说到虚析构函数,我们先来看看析构函数的作用:在删除指向动态分配对象的指针时,需要运行析构函数在释放对象的内存之前清除对象。
在处理继承层次的对象时,指针的静态类型可能与被删除对象的动态类型不符,可能会删除实际指向派生类对象的基类类型指针。
怎么理解这句话呢,在有继承的时候,如果我们删除一个指向子类的基类类型的指针F,也就是说指针F的类型是基类,但这个指针指向子类。这个时候如果要删除这个指针,调用的应该是基类的析构函数。如下代码:
1 //base.h 2 3 #include <iostream> 4 5 using namespace std; 6 7 class A{ 8 public: 9 A() { 10 cout << "A" << endl; 11 } 12 ~A() { 13 cout << "~A" << endl; 14 } 15 }; 16 17 class B: public A{ 18 public: 19 B() { 20 cout << "B" << endl; 21 } 22 ~B() { 23 cout << "~B" << endl; 24 } 25 };
1 //main.cpp 2 3 #include"base.h" 4 #include<iostream> 5 6 using namespace std; 7 8 int main(int argc,char*argv[]) 9 { 10 A* te = new B; 11 delete te; 12 return 0; 13 }
运行结果是:
A B ~A 请按任意键继续. . .
但是实际上对象是B类型的,也就是说应该调用B的析构函数才对。
我们来考虑一种情况,当类B中有一个新的函数,改函数开出了一个内存空间,如new 出了一个对象。那么在删除指针F的时候,我们调用的是基类的析构函数,但基类的析构函数没有释放类B中的那个函数开出的空间,就会造成内存泄漏。为了解决这个问题,我们必须另基类的析构函数为虚函数。
如果基类的析构函数为虚函数,那么通过指针调用时,运行哪个析构函数将因指针所指的对象类型的不同而不同。
如下:
1 #include <iostream> 2 3 using namespace std; 4 5 class A{ 6 public: 7 A() { 8 cout << "A" << endl; 9 } 10 virtual ~A() { 11 cout << "~A" << endl; 12 } 13 }; 14 15 class B: public A{ 16 public: 17 B() { 18 cout << "B" << endl; 19 } 20 ~B() { 21 cout << "~B" << endl; 22 } 23 };
运行结果:
A B ~B ~A 请按任意键继续. . .
像其他虚函数一样,析构函数的虚函数性质都将继承。因此,如果层次中根类的析构函数为虚函数,那么派生类的析构函数也将是虚函数,无论派生类显式定义析构函数还是使用合成析构函数,派生类的析构函数都是虚函数。
因此,为了程序的正常运行,就算析构函数没有工作要做,继承层次的根类也应该定义一个虚析构函数。
原文:http://www.cnblogs.com/xiezhw3/p/3545220.html