第一步:
調試過程中發現,在CSingleDocTemplate的構造函數中初始化了CSingleDocTemplate成員變量m_pOnlyDoc = NULL;
並調用父類CDocTemplate的構造函數,在父類的構造函數中初始化了三個成員變量:
CRuntimeClass*m_pDocClass =RUNTIME_CALSS(CSdiDoc);
CRuntimeClass*m_pFrameClass = RUNTIME_CALSS(CSdiFrm);
CRuntimeClass*m_pViewClass = RUNTIME_CALSS(CSdiView);
第二步:
調用CWinApp的AddDocTemplate,進入函數內部:
實參是:pDocTemp(CSingleDocTemplate)。
CWinApp中有一個m_pDocManager(CDocManager)的指針。
在CWinApp::AddDocTemplate函數內部實例化了m_pDocManager,
並調用m_pDocManager的CDocManager::AddDocTemplate函數。
下面是該函數的內部實現過程(省略次要部分):
實參:pDocTemp(CSingleDocTemplate)
void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)
{
if(…)
{…}
else
{
…
pTemplate->LoadTemplate();//內部執行可以不用關心
m_templateList.AddTail(pTemplate);
}
}
//CDocManager中有一個成員:m_templateList
m_templateList.AddTail(pTemplate);//內部實現過程:
使用尾插法將pTemplate插入到m_templateList鏈表的尾部。
第三步:
OnFileNew();函數的內部實現過程:
void CWinApp::OnFileNew()
{
//m_pDocManager在第二步CWinApp::AddDocTemplate中已經實例化了
if (m_pDocManager != NULL)
m_pDocManager->OnFileNew();
}
補充:m_pDocManager成員函數:OnFileNew(),
AddDocTemplate(CDocTemplate* pTemplate)。
m_pDocManager->OnFileNew();//內部實現過程:
void CDocManager::OnFileNew()
{
//在CDocManager::AddDocTemplate中添加了一個單文檔模板到m_templateList的尾部,所以此處不爲空
if (m_templateList.IsEmpty())
{… }
//獲取模板鏈表的第一個元素,此時拿到的是我們之前添加的單文檔模板
//如果有多個模板,會彈出對話框,讓用戶選擇
CDocTemplate*pTemplate= (CDocTemplate*)m_templateList.GetHead();
if (m_templateList.GetCount() > 1)
{
CNewTypeDlg dlg(&m_templateList);
int nID = dlg.DoModal();
if (nID == IDOK)
pTemplate = dlg.m_pSelectedTemplate;
else
return;
}
//pTemplate是我們之前添加的單文檔模板,創建frame,創建文檔
pTemplate->OpenDocumentFile(NULL);
}
pTemplate->OpenDocumentFile(NULL);//內部實現過程:
CDocument *CSingleDocTemplate::OpenDocumentFile(
LPCTSTR lpszPathName, BOOL bMakeVisible)
{
CDocument* pDocument = NULL;
CFrameWnd* pFrame = NULL;
//此時m_pOnlyDoc(CSingleDocTemplate)依舊爲空
if (m_pOnlyDoc != NULL)
{…. }
else
{
//父類的成員函數,創建新文檔,給m_pOnlyDoc賦值
pDocument = CreateNewDocument();
}
ASSERT(pDocument == m_pOnlyDoc);//成功調用上面的函數,兩者必然相等
if (pFrame == NULL)
{
…
pFrame = CreateNewFrame(pDocument, NULL);
…
}
CWinThread* pThread = AfxGetThread();//主線程
if (bCreated && pThread->m_pMainWnd == NULL)
{
pThread->m_pMainWnd = pFrame;//設置主窗口
}
InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
// InitialUpdateFrame內部實現過程:
pFrame->InitialUpdateFrame(pDoc, bMakeVisible);
return pDocument;//返回創建的pDocument
}// OpenDocumentFile函數結尾
pDocument = CreateNewDocument();//內部實現過程:
CDocument* CDocTemplate::CreateNewDocument()
{
…
CDocument *pDocument =(CDocument*)m_pDocClass->CreateObject();
//m_pDocClass是RUNTIME_CLASS(CSdiDoc),
//在初始化CSingleDocTemplate傳進來的參數。補充:m_pDocClass是文檔模板類(CDocTemplate)的成員變量
…
AddDocument(pDocument);//CSingleDocTemplate的成員函數
return pDocument;
}
AddDocument(pDocument);//內部實現過程:
void CSingleDocTemplate::AddDocument(CDocument* pDoc)
{
CDocTemplate::AddDocument(pDoc);//調用父類的
m_pOnlyDoc = pDoc;//將剛創建的文檔對象賦值給CSingleDocTemplate的成員變量。終於在這裏賦值了!
}
pFrame = CreateNewFrame(pDocument, NULL);//內部實現過程:
CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther)
{
CCreateContext context;
context.m_pCurrentFrame = pOther;//pOther=NULL
context.m_pCurrentDoc = pDoc;//傳進來的實參
context.m_pNewViewClass=m_pViewClass;
//RUNTIME_CALSS(CSdiView)
context.m_pNewDocTemplate = this;
//this:CSingDocTemplate
CFrameWnd*pFrame = (CFrameWnd*)m_pFrameClass->CreateObject();
if (!pFrame->LoadFrame(m_nIDResource,
WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,
NULL, &context)
)
{…..}
return pFrame;//返回創建好的frame
}
最後一步:
小結:
CWinApp中有一個m_pDocManager指針,m_pDocManager有一個成員變量m_templateList,維護了一個模板鏈表。CSingleDocTemplate中有一個m_pOnlyDoc,維護了一個文檔指針。
CWinApp的父類CWinThread中有一個m_pMainWnd指針,維護了Frame窗口。
CFrameWnd中有一個SetActiveView(),維護了View。
CView中有一個CDocument*m_pDocument,保存了文檔指針。
CDocument中有一個m_viewList; 維護了一個視圖鏈表。