一个好的C++程序,应有一套谨慎的逻辑结构,一套严密的资源管理方法。其中资源管理总是最容易出现纰漏的地方,很多时候我们会忽略一个或多个delete/operator delete,或者我们写了清理代码,却没意识到它可能不会被执行。第一种情况自不必多说,而第二种情况可能就让人有些疑惑了。既然我写了它用来清理不需要的资源,那我必然会显式调用它或者编译器会自动调用它,怎么还能说不会被执行呢?对于这种情况,我能想到的有两种可能:
1.使用多态性操作时,它被忽略了;
2.异常影响了调用。
对于第一点,我们可以先来分析一段代码:
1 class base 2 { 3 private: 4 protected: 5 public: 6 base() { cout << "Base's Constructor is Called!" << endl; } 7 virtual ~base() { cout << "Base's Destructor is Called!" << endl; } 8 }; 9 10 class derived : public base 11 { 12 private: 13 protected: 14 public: 15 derived() : base() { cout << "Derived's Constructor is Called!" << endl; } 16 ~derived() { cout << "Derived's Destructor is Called!" << endl; } 17 }; 18 19 derived* GetDerived() 20 { 21 return new derived(); 22 }
以上是一个基类与一个派生类的声明,及一个返回派生类指针的操作。接下来,我将在主函数里,进行一个常规操作以及一个多态性操作,我们可以观察其运行结果:
1 int main() 2 { 3 base *pb = GetDerived(); 4 delete pb; 5 derived *pd = GetDerived(); 6 delete pd; 7 8 return 0; 9 }

仔细观察运行结果,我们可以发现,第一次,我将派生类指针赋给基类指针(这是可行的),并将基类指针进行删除,由此,我们可以看到基类构造、派生类构造函数的调用,还有基类析构函数的调用,等等!问题出现了,派生类析构函数未得到调用。这里,我先说解决的办法:我们可以在析构函数前加上virtual,使其成为虚析构函数,然后再执行同样的操作,我们可以看到,将派生类指针赋给基类指针使用时派生类析构函数也被调用了。
之所以会如此,是因为编译器对virtual方法的处理。对于非virtual方法,编译器执行静态联编,也就是说,我使用的是基类指针,它就仅有基类操作;对于virtual方法,编译器使用动态联编,虽然我使用基类指针,但编译器此时会知道,这个指针指向的其实是一个派生类对象,如此多态性就体现了。
以上的例子仅仅是为了清晰呈现virtual与非virtual的区别,在实际编码中,我们需要的是更严谨的态度,若少了一步,则某些清理工作可能不会得到执行,就将造成资源的浪费,所以我们要做的是善用虚析构函数。对于,上面提过了两种情况,第二种异常情况,将在后续文里提到,本文就不在赘述了。