看了一篇讲c++内存管理的长博,感叹作者的牛逼之余也加点儿梗吧。。。
贴出博客地址:c++内存管理-- oayx大神!http://www.cnblogs.com/lancidie/archive/2011/08/05/2128318.html
tips:在类内,多态基类的析构函数应该为虚函数
根据c++多态特性,当我们的基类指针指向子类对象时,当我们调用基类指针的某个函数为虚函数,则我们调用的是子类的该函数,否则调用基类的该函数。。。
这样说貌似说不清楚,之前写(chao)过一篇讲虚函数的博客,嗯,将就着看看吧...http://blog.csdn.net/wstzone/article/details/39374287
然后,辣就上代码吧。。。
class Employee { <span style="white-space:pre"> </span>public: <span style="white-space:pre"> </span>Employee(); <span style="white-space:pre"> </span>~Employee(); <span style="white-space:pre"> </span>... }; class Programer : public Employee { <span style="white-space:pre"> </span>public: <span style="white-space:pre"> </span>Programer(); <span style="white-space:pre"> </span>~Programer(); <span style="white-space:pre"> </span>... }; class Tester : public Employee { <span style="white-space:pre"> </span>public: <span style="white-space:pre"> </span>Tester(); <span style="white-space:pre"> </span>~Tester(); <span style="white-space:pre"> </span>... };
这个时候假如我们执行
Employee * pEmployee = createEmployee(type);//这里new 一个type对象,type是各个子类 ...// delete pEmployee;//problem shows up
其实我们的想法是美好的,我们new 了一个对象,然后删除了一个对象有木有。。。
但是其实我们new的是子类对象,new调用的是子类对象的构造函数;delete了基类对象,delete调用的却是基类的析构函数!
结果我们就变成了只删除了子类对象中的基类部分,并未完全删除。。。会导致问题你懂的。。。
但是,如果我们把基类的析构函数设置为virtual的虚函数,辣么我们这个流程就变得正确了,c++会正确的调用整个析构链,销毁整个对象。。
即:
class Employee { <span style="white-space:pre"> </span>public: <span style="white-space:pre"> </span>Employee();
<span style="white-space:pre"> </span>virtual ~Employee(); <span style="white-space:pre"> </span>... };
注意,我们说的是多态基类(这样的类必然会需要包含其他的虚函数才能称得上多态基类吧)这样做是正确的,但当我们的类不包含其他虚函数时,辣就最好别这样做,因为虚函数表会导致类对象大小的增大,并且因为结构的变化也会失去部分可移植性。
另外,不能将构造函数设置为虚构函数。。。这个应该毫无疑问的吧,问一下why:
无论对象在哪里构建,我们new 一个对象的时候做两件事:1.分配一块内存;2调用构造函数
然后其实构造函数要做的事情之一就是初始化类的虚函数表。。如果构造函数是虚函数,辣么我们需要通过虚函数表来调用构造函数,呃,死循环。。。