為了便於解釋,假設SDI應用測試已經由應用向導生成,包括諸如CT ESTAPP、CT ESTDoc、CT ESTView、CMAIN FRM之類的類。
1.從視圖類中獲取文檔類的指針。
如前所述,在需要引用視圖類中的文檔類之前,使用以下語句:
CTextDoc * pDoc =(CTestDoc *)get document();
以後可以使用pDoc指針來訪問文檔類。
這裏的強制類型轉換在測試應用中是沒有必要的,因為程序中只有壹個view類,而且是用Initstance()中的SDI文檔模板組裝的。您可以在Test.cpp的Initstance()方法中看到以下語句:
CSingleDocTemplate * PDO template;
pDocTemplate = new CSingleDocTemplate(IDR _ MAINFRAME,RUNTIME_CLASS(CTestDoc),RUNTIME_CLASS(CMainFrame),
RUNTIME _ CLASS(ctest view));
AddDocTemplate(pDocTemplate);
以及TestView.h中的在線定義:
內聯CTestDoc * ctest view::get document()
{ return(CTestDoc *)m _ p document;}
簡而言之,CTestView的GetDocument()函數很自然地認為CTestDoc與之“匹配”。當生成具有多個視圖類的應用程序時(例如,使用CSplitterWnd),窗口被分成兩列,但這兩列不是從同壹個視圖類派生的,情況就是這樣。具體實現不在本文討論範圍內),壹個視圖類只能和壹個唯壹的文檔類用壹個文檔模板組裝,所以需要強制類型轉換,才能獲得另壹個未組裝類中文檔類的指針。
2.從文檔類中獲取壹個指向視圖類的指針。
CDocument類提供了兩個定位視圖類的函數:GetFirstViewPosition()和GetNextView()。具體語法如下:
虛擬位置GetFirstViewPosition()const;
虛擬CView* GetNextView(位置& ampr position)const;
註意:引用了GetNextView()括號中的參數,所以執行後值可能會改變。
GetFirstViewPosition()用於返回第壹個視圖位置(不是視圖類指針,而是返回壹個位置類型值),GetNextView()有兩個作用:返回下壹個視圖類的指針,通過引用傳遞改變傳遞的位置類型參數的值。很明顯,在測試程序中,只有壹個view類,所以只需要調用這兩個函數壹次就可以得到CTestView的指針如下(需要定義壹個POSITION結構變量來輔助操作):
CTestView * pTestView
POSITION pos = GetFirstViewPosition();
ptest view = get next view(pos);
這樣我們就可以得到CTestView類的指針pTestView。執行幾句後,變量pos=NULL,因為沒有下壹個視圖類,自然也就沒有下壹個視圖類的位置。
但有幾句過於簡單,不具備很強的通用性和安全特性;如前所述,當我們想要在多個視圖中返回指向指定類的指針時,我們需要遍歷所有視圖類,直到找到指定的類。在判斷類指針是否指向類的實例時,可以使用IsKindOf()成員函數來檢查時間線,比如:
pView-& gt;IsKindOf(RUNTIME _ CLASS(ctest view));
可以檢查pView是否引用了CTestView類。
有了上面的基礎,我們已經可以從document類獲得指向任何類的指針了。為了方便起見,我們把它看作壹個文檔類的成員函數,它有壹個參數指示要獲取指向哪個類的指針。實現如下:
CView * CTestDoc::GetVieww(CRuntimeClass * pClass)
{ CView * pView
POSITION pos = GetFirstViewPosition();
while(pos!=空)
{
pView = get next view(pos);
if(pView-& gt;IsKindOf(pClass))
打破;
}
如果(!pView-& gt;IsKindOf(pClass))
返回NULL
返回pView}
view類的成員函數IsKindOf()用了兩次來判斷,因為退出while循環有三種可能:
1.pos為空,即沒有下壹個視圖類進行操作;
2.pView已滿足要求。
3.1和2都滿足。這是因為GetNextView()的作用是將當前視圖指針改變到壹個視圖的位置,同時返回當前視圖指針,所以pos是pView的下壹個視圖類的位置,完全有可能同時是pos==NULL和pView。當所需視圖是最後壹個視圖和最後壹個視圖類時,就像壹個引用。所以需要兩個判斷。
使用該函數時應遵循以下格式(以CTestView指針為例):
ctest view * ptest view =(ctest view *)GetView(RUNTIME _ CLASS(ctest view));
RUNTIME_CLASS是壹個宏,它的作用可以簡單的理解為:把壹個類的名字轉換成壹個CRuntimeClass作為指針。
至於強制類型轉換,也是出於安全特性的考慮,因為來自同壹個基類的指針類型是相互兼容的。這種強制的類型轉換可能不是必須的,但是可以避免壹些可能的麻煩。
3.獲取從壹個視圖類到另壹個視圖類的指針。
結合1和2,很容易得到視圖類之間獲取指針的方法:以文檔類為中轉,先通過1獲取文檔類的指針,再通過2使用文檔類的視圖定位函數獲取另壹個視圖類。同樣,它可以作為壹個函數來實現:
(假設您想從CTestAView獲取指向其他視圖類的指針)
CView * cte staview::GetView(CRuntimeClass * pClass)
{ CTestDoc * pDoc =(CTestDoc *)get document();
CView * pView
POSITION pos=pDoc->。GetFirstViewPosition();
while(pos!=空)
{
pView = pDoc-& gt;get next view(pos);
if(pView-& gt;IsKindOf(pClass))
打破;
}
如果(!pView-& gt;IsKindOf(pClass))
返回NULL
返回pView}
與2中的GetView()相比,該函數增加了第壹句獲取文檔類指針,並在GetFirstViewPosition()和GetNextView()前增加了文檔類指針,表示它們是文檔類成員函數。
有了這個功能;當妳想從CTestAView中獲取壹個指向CTestBView的指針時,妳只需要做以下事情:
ctest bview * ptest bview =(ctest view *)GetView(RUNTIME _ CLASS(ctest bview));
4.從主框架窗口類獲取視圖類指針。
對於本文中提到的SDI程序,這很簡單,測試使用CFrameWnd類的GetActiveView()成員函數。格式如下:
CFrameWnd::GetActiveView()
但是,當這個函數應用於MDI應用程序時,並沒有像預期的那樣獲得當前活動子窗口的視圖類,而是返回NULL,這是壹個必然的問題。在MDI程序中,CMDIFrameWnd與任何視圖類都沒有關系,也就是說沒有任何視圖類直接屬於它,只有子幀窗口類CMDIChildWnd是所有子窗口視圖類的父窗口。子幀窗口的父窗口是CFrameWnd。因此,MDI程序中獲取活動視圖類的正確方法是先獲取活動子幀窗口,再從活動子幀窗口獲取活動視圖類:
//獲取活動子幀窗口
CMDIChildWnd * pChild =(CMDIChildWnd *)GetActiveFrame();
//或者:cmdichildwnd * pchild = mdigetactive();
//獲取活動子幀窗口的活動視圖。
cmy view * pView =(cmy view *)pChild-& gt;GetActiveView();
5.從視圖類中獲取主框架窗口類指針:
使用函數:CWnd::GetParentFrame()或AfxGetMainWnd();
能達到目的。GetParentFrame()的工作方式是在父窗口鏈中搜索,直到找到CFrameWnd或其派生類,並返回其指針。InfoViewer中詳細介紹了用法。
6.獲取任何類中的應用程序類。
可以用MFC全局函數AfxGetApp()來完成。
7.從應用程序類中獲取主框架窗口類。
cwintohread類有壹個名為m_pMainWnd的數據成員。由於CWinApp類是從cwintohread派生的,而我們的應用程序是從CWinApp派生的,所以我們的CTestApp類也有壹個名為m_pMainWnd的成員,它指導CMainFrame類。(需要適當的石膏)。
綜上所述,有幾點需要註意:
A.在a類中獲取指向b類的指針時,a類應該包含b類的頭文件。
B.很多情況下需要強制類型轉換,要註意括號。
由於派生類和父類的指針類型的兼容性,區分清楚每個類是非常重要的。當有疑問時,最好添加強制類型轉換。