题:MFC类库中,CObject类的重要性不言自明。在CObject的定义中,我们看到一个有趣的现象,即CObject的析构函数是虚拟的。为什么MFC的编写者认为virtual destructors are necessary(虚拟的析构函数是必须的)?【美国某著名移动通信企业2004年面试题】
解析:我们可以先构造一个类如下:
class CBase
{
public:
~CBase(){......}
......
};
class CChild : public CBase
{
public:
~CChild(){......}
......
};
int main()
{
CChild c;
......
return 0;
}
上面的代码在运行时,由于在生成CChild对象c时,实际上在调用CChild类的构造函数之前必须首先调用其基类CBase的构造函数,所以当撤销c时,也会在调用CChild类析构函数之后,调用CBase类的析构函数(析构函数调用顺序与构造函数相反)。也就是说,无论析构函数是不是虚函数,派生类对象被撤销时,肯定会依次上调其基类的析构函数。
那么为什么CObject类要搞一个虚的析构函数呢?
因为多态的存在。
仍以上面的代码为例,如果main()中有如下代码:
CBase *pBase;
CChild c;
pBase = &c;
那么在pBase指针被撤销时,调用的是CBase的析构函数还是CChild的呢?显然是CBase的(静态联编)析构函数。但如果把CBase类的析构函数改成virtual型,当pBase指针被撤销时,就会先调用CChild类的析构函数,在调用CBase类的析构函数。
答案:在这个例子中,所有对象都存在于栈框中,当离开其所处的作用域时,该对象会被自动撤销,似乎看不出什么大问题。但是试想,如果CChild类的构造函数在堆中分配了内存,而其析构函数又不是virtual型的,那么撤销pBase时,将不会调用CChild::~CChild(),从而不会释放CChild::CChild()占据的内存,造成内存泄漏。
将CObject的析构函数设为virtual型,则所有CObject类的派生类的析构函数都将自动变为virtual型,这保证了在任何情况下,不会出现由于析构函数未被调用而导致的内存泄漏。这才是MFC将CObject::~CObject()设为virtual型的真正原因。