?? 1130572592109[1].面試常見問題解答1:co.txt
字號:
面試常見問題解答1:CObject類中的析構函數為什么是虛函數ZZ
shury 發表于 2004-12-7 20:24:00
[寶寶提供的答案僅供參考,如有不對歡迎指正]
面試SE時,很多公司喜歡問到虛函數相關。寶寶有一次被問到,CObject類中的析構函數為什么是虛函數,不懂。后來上網查到了答案,特貼上來與大家分享
MFC類庫中,CObject類的重要性不言自明的。在CObject的定義中,我們
看到一個有趣的現象,即CObject的析構函數是虛擬的。
在AFX.H中,CObject的定義:
class CObject
{
public:
// Object model (types, destruction, allocation)
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); //virtual destructors are necessary
...
...
};
為什么MFC的編寫者認為virtual destructors are necessary
(虛擬的析構函數是必要的)?
在著名的VC教程 "精通Visual C++ for Windows 95/NT"(電子工業版,
1997年5月版,胡儉,丘宗明等著)第99頁中有這樣一段話:
“如果CObject的析構函數不是虛擬的,派生類就不會自動地得到虛擬的
析構函數,當對象撤消時就會帶來問題——只有當前類的析構函數得到
調用而基類的析構函數就得不到調用。...”
我認為這段解釋是這本很不錯的書中一個不應出現的嚴重錯誤。其意思是說:
若:
class CBase
{
public:
~CBase() { ... };
...
};
class CChild : public CBase
{
public:
~CChild() { ... };
...
};
main()
{
Child c;
...
return 0;
}
上段代碼在運行時,當棧框中的自動對象 c 被撤消時,只調用~CChild(),
而不調用~CBase()。
我想但凡對C++繼承性理論有所了解的人都會立刻指出這是錯誤的。
由于在生成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型的真正原因。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -