第一步:
调试过程中发现,在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; 维护了一个视图链表。