如果我們要將一個控件轉(zhuǎn)換成視圖類,,我們一般會想到CCtrlView,,用它實現(xiàn)的控件視圖一般添加一個GetXXXCtrl函數(shù),函數(shù)的作用是返回視圖中控件的引用,,如果在MFC程序中跟蹤它的調(diào)用我們會發(fā)現(xiàn)它的實現(xiàn)是這樣的(以CEdit控件為例) _AFXEXT_INLINE CEdit& CEditView::GetEditCtrl() const 這個轉(zhuǎn)換讓人覺得很疑惑,,因為CEdit和CEditView是來自兩條不同繼承鏈上的類,一般來說這樣的轉(zhuǎn)換是要出問題的,,但是為什么可以進行這種轉(zhuǎn)換,?MSDN上有一篇文章對這種轉(zhuǎn)換做了比較深入的解釋,下面把這篇文章翻出來給大家看看,。 問題: Mateo Anderson(回答者) 回答: CTreeView::CTreeView() : 在這個例子中,WC_TREEVIEW(在commctrl.h中定義)是樹型控件類的類名,,也就是“SysTreeView32”,。CCtrlView會將此類名保存在一個數(shù)據(jù)成員中稍后使用: CCtrlView::CCtrlView(LPCTSTR lpszClass, 下一個起作用的函數(shù)是PreCreateWindows,這是一個CTreeCtrl從CCtrlView繼承來的函數(shù),。CCtrlView::PreCreateWindow在窗口剛好創(chuàng)建完成之前使用m_strClass在CREATESTRUCT種設(shè)置類名,。 // CCtrlView uses stored class name 現(xiàn)在創(chuàng)建的窗口就是使用所期望的類創(chuàng)建的了-在這個例子中就是SysTreeView32。到目前為止,,一切都很好,。但是如果CTreeCtrl派生于CCtrlView,而CCtrlView又派生于CView,,那么它為什么能又派生于CTreeCtrl,?難道是MFC類封裝了樹型控件?CTreeView和CTreeCtrl是完全獨立的,,有著不同的繼承鏈,。CTreeCtrl直接派生于CWnd,而CTreeView派生于CCtrlView/CView,。這就是技巧發(fā)生作用的地方了,。要讓樹型視圖像樹型控件一樣操控,CCtreeView提供了特殊的函數(shù)GetTreeCtrl來獲得樹型控件,。 CTreeCtrl& CTreeView::GetTreeCtrl() const GetTreeCtrl只是簡單的將CtreeView轉(zhuǎn)換為CTreeCtrl,。但是等等-怎么會發(fā)生這么詭異的事?這兩個類完全不同,,有著不同的數(shù)據(jù)成員和虛函數(shù)表-你根本無法將一個轉(zhuǎn)換成另一個同時還指望著能夠正常工作,!答案就是:CTreeCtrl沒有虛函數(shù)也沒有數(shù)據(jù)成員。你可以把它稱為一個純包裝類,。CTreeCtrl不對它的基類CWnd添加任何東西(不添加數(shù)據(jù)成員也不添加虛函數(shù)),,所有添加的內(nèi)容只是一些包裝函數(shù),一些將消息發(fā)送給內(nèi)在HWND的有形函數(shù),。 HTREEITEM CTreeCtrl::InsertItem(...) InsertItem訪問的唯一數(shù)據(jù)成員是m_hWnd,,所有的CWnd派生類都有該成員。InsertItem和所有其它的包裝函數(shù)只是將它們的參數(shù)傳遞給了內(nèi)在的HWND,,將C++風格的成員函數(shù)轉(zhuǎn)換成Windows風格的SendMessage調(diào)用,。對象本身(“this”指針)可以是任何CWnd派生類的實例,只要m_hWnd處于正確的位置(也即是類的第一個數(shù)據(jù)成員),,并且HWND(實際上就是如此)是一個樹型控件的句柄,。相同的原因發(fā)生在下面的寫法中: 即便在這里GetDlgItem返回的是一個指向CWnd的指針,,不是CEdit。但是這樣是允許的,,因為CEdit也是一個包裝類,,而且對于它從CWnd繼承來的內(nèi)容沒有添加額外的數(shù)據(jù)和虛函數(shù)。所以注釋中“CCtrlView幾乎允許將任何控件轉(zhuǎn)換為視圖”的說法中所說的“幾乎任何”意思是特指對CWnd沒有添加數(shù)據(jù)成員和虛函數(shù)的這些控件,,也就是我所說的“純包裝類,。”如果你的控件類有它自己的數(shù)據(jù)或虛函數(shù),,你無法使用CCtrlView,,因為在CCtrlView/CView中不存在這些額外的數(shù)據(jù)成員和虛函數(shù)。 舉例來說,,CView中的第一個虛函數(shù)是CView::IsSelected,。如果你的控件類有其它虛函數(shù),在你把CCtrlView類轉(zhuǎn)換成你的CFooCtrl類調(diào)用那個虛函數(shù)的時候就肯定會爆發(fā)問題了,,因為這個函數(shù)根本不存在,。類似的,CView中的第一個數(shù)據(jù)成員是m_pDocument,。如果你的控件類需要一些其它的數(shù)據(jù)成員,,那你在訪問它們的時候就要倒霉了,因為對象事實上調(diào)用的是CCtrlView,,而不是CFooCtrl,。多么糟糕,多么令人沮喪,。
|
|