精華區beta CompBook 關於我們 聯絡資訊
【虛擬解構式 virtual destructor】 侯捷 jjhou@ccca.nctu.edu.tw 1999.10.09 第一次發表於 清大.楓橋驛站(140.114.87.5).電腦書訊版(Computer/CompBook) 本文將於日後整理於 侯捷網站/電腦散文/散文1999 侯捷網站:www.jjhou.com ---------------------------------------------------------------- ●大陸讀者來函 (註:兩案的計算機術語多有不同,我已轉為英文表達) 寄件者: yhd <yd2000@263.net> 收件者: jjhou@cca.nctu.edu.tw <jjhou@ccca.nctu.edu.tw> 日期: 1999年9月12日 PM 05:12 主旨: 求救(簡體中文) > 侯老師: > 您好,我想請教一個問題。我拜讀了《深入淺出 WINDOWS MFC > 程序設計》(華中理工大學出版社),收益非淺,尤其是書中 > 例子的講解,是我見過最精彩的。但是在Scribble例子中, > 你只講了在文件檔中使用一個 CStroke﹐我想如果還有其他如 > CRect、CLine等,在 CScribbleDoc 中的 list 物件該怎樣定義呢? > 我編寫了一個程序,所有繪圖類別都從一個叫 CBaseElement > 的 class 繼承而來,CBaseElement 從 CObject 繼承而來,在 > CBaseElement 中定義了一些 virtual function。在 DOC 中 > 定義 CTypedPtrList<CObList,CBaseElement*>m_elementList > 的物件指標。但是我發現一個問題﹐就是在刪除這些繪圖物件時, > 由於使用的是一個 CBaseElement base class 指標,它不會呼叫 > derived class 的 destructor。應怎樣辦呢?望您百忙之中能 > 抽空回答我!無論怎樣,都謝謝您和您的書給我的幫助。謝謝! > 海棟 > 99年9月11日 ●永遠的習題 我在元智開了四個學期的「Object Oriented Windows Programming, using MFC」,使用《深入淺出 MFC》做教材。每學期只有一個作業, 就是把 Scribble 範例改寫為一個繪圖程式。改得多改得好,分數高。 改得少改得不好,分數低。改不動,不及格。 有些同學只是把 Scribble 的畫筆加上顏色選擇。這種程式一律 60 分。你得到了學分,但是喪失學習 OO 一個很棒的機會。有些 同學表現很好,抓住精髓,使用 polymorphism 來完成目標。 ●正確的改法 海棟先生的改法是正確的。把原本的: CTypedPtrList<CObList,CStroke*>m_elementList; 改為: CTypedPtrList<CObList,CBaseElement*>m_elementList; 而讓 CBaseElement 繼承 CObject(以保有 MFC 的 Serializable、 dynamic creation、RTTI 性質),又讓所有繪圖用的 classes (如 CRectangle、CLine...)繼承 CBaseElement。 當程式 UI 部份處理了繪圖命令之後,程式的資料結構部份 便應該以 CBaseElement* 型別 new 出一個具體形狀 (例如 CRectangle): CBaseElement* pobj = new CRectangle; // polymorphically 然後接受座標資料的輸入,然後加入 m_elementList 之中。 ●海棟的問題 海棟先生的問題是,每次要 delete 一個繪圖物件時,從 list 中 取出指標,然後做 delete 動作。結果,由於指標的型別是 CBaseElement*,所以只會喚起 CBaseElement 的 destructor。 即使該繪圖物件其實是個 CRectangle object,CRectangle 的 destructor 並不會被喚起。 這當然是不好的。 ●虛擬解構式(virtual destructor) 解決之道很簡單,把 CBaseElement 的 destructor 宣告 為 virtual 就好了。是的,virtual destructor 就是用來 解決這種問題。 拙作《多型與虛擬》p.59 小節講的便是這個主題。 (此書並無大陸簡體版。我本打算 2/e 再授權給大陸。 不過現在已經暫時封筆) Effective C++ (Scott Meyers/Addison Wesley)書中 item 14 : Make destructor virtual in base classes. 講的也是這個主題。 ●工業強度 你在改寫 Scribble 範例時想到上述問題,大約是因為兩種情況: (1) 該程式本來就有一個 [delete all] 選單命令,為了 讓它可以正常運行,你必須考慮對 list 中的所有物件一一 做正確的 delete 動作。 (2) 你更進一步想要讓使用者「有選擇性地」刪除某個繪圖物件。 (2) 的學問可就大了。能夠讓使用者以滑鼠在螢幕上「精準而 快速回應」地點選某個繪圖物件,是件不容易的事。具工業強度! 這種情況從 CAD 軟體開始發展以來,就存在。 --- then end -- ※ Origin: 楓橋驛站<bbs.cs.nthu.edu.tw> ◆ Mail: jjhou@ccca.nctu.edu.tw