您的位置:首页 > 其它

学习笔记之深入浅出MFC 第9章 仿真MFC 之一

2016-05-06 09:27 330 查看
在文章开始是我们的观点就强调过了,要想用好一个工具,就必须深入了解这个工具的工作原理。而仿真,正是最好的方法。

如何仿真呢?我们在console程序中仿真MFC,这样可以把程序结构的负荷降到最低。作者在仿真中的原则是:简化再简化,简化到不能再简化。请注意,以下所有程序的类层次结构、类名称、变量名称、结构名称、函数名称、函数内容,都以MFC为仿真对象,具体而微。

在档案的安排上,作者把仿真MFC的类集中在MFC.H和MFC.CPP中,把自己派生的类集中在MY.H和MY.CPP中。对于自定义的类,我的命名方式是在父类的名称前面加一个“My”,例如派生自CWinApp者,名为CMyWinApp,派生自CDocument者,名为CMyDoc。

特别说明:我一直认为,扎实的基础是以后进阶高度快速提升的不二法门,所以希望大家能够跟着我沉住气,一点一点挖出MFC整个的运行机制,相信这会对大家和对我自己更有裨益。从这一章开始,我会分析的很细,可能每一节讲的很少,但务必求精不贪多,希望大家可以理解。

1、MFC的类层次结构

首先以一个极简单的程序Frame1,把MFC数个最重要的类的层次关系仿真出来:



这个例程仿真MFC的类层次。后续会在这个类层次上开发新的能力。在这些名为Frame?的范例中,我以MFC程序代码为蓝本,尽量仿真MFC的内部行为,并且使用完全相同的类名称、函数名称、变量名称。这会对我们在后面深入探讨MFC时有莫大的助益。

Frame 1 范例程序

首先是MFC.H头文件:

#include  <iostream>

using namespace std;

class  CObject      //基类CObject

{

public:

CObject::CObject()  { cout << "CObject  Constructor  \n";  }  

CObject::~CObject()  {cout << "CObject  Destructor  \n";  };

};

class  CCmdTarget  :  public  CObject

{

public:

CCmdTarget::CCmdTarget()  { cout << "CCmdTarget  Constructor  \n";  }  

CCmdTarget::~CCmdTarget()  {cout << "CCmdTarget  Destructor  \n";  };

};

class  CWinThread  :  public  CCmdTarget

{

public:

CWinThread::CWinThread()  { cout << "CWinThread  Constructor  \n";  }  

CWinThread::~CWinThread()  {cout << "CWinThread  Destructor  \n";  };

};

class  CWinApp  :  public  CWinThread

{

public:

CWinApp* m_pCurrentWinApp;

public:

CWinApp::CWinApp()   { m_pCurrentWinApp = this;

cout << "CWinApp  Constructor \n"; }   //这个类的对象在创建时就会调用构造函数,所以也就把当前类对象指针保存到了m_pCurrentWinAPP

CWinApp::~CWinApp()  { cout << "CWinApp  Destructor  \n"; }

};

class  CWnd  :  public  CCmdTarget

{

public:

CWnd::CWnd()  { cout << "CWnd  Constructor  \n";  }

CWnd::~CWnd()  { cout << "CWnd  Destructor  \n";  }

};

class  CFrameWnd  :  public  CWnd

{

public:

CFrameWnd::CFrameWnd()  { cout << "CFrameWnd  Constructor  \n";  }

CFrameWnd::~CFrameWnd()  { cout << "CFrameWnd  Destructor  \n";  }

};

class  CView  :  public  CWnd

{

public:

CView::CView()  { cout << "CView  Constructor  \n";  }

CView::~CView()  { cout << "CView  Destructor  \n";  }

};

//全局函数

CWinApp*  AfxGetApp();

然后是MFC.CPP:

#include "MFC.h"

#include "MY.h"

extern  CMyWinApp  theApp;

CWinApp*  AfxGetApp()

{

return  theApp.m_pCurrentWinApp;

}

接下来是从MFC类中派生出来的我们自己的App类:

MY.H头文件:

#include <iostream>

#include "MFC.h"

class CMyWinApp  :  public  CWinApp

{

public:

CMyWinApp::CMyWinApp()   {  cout << "CMyWinApp  Constructor  \n"; }

CMyWinApp::~CMyWinApp()   {  cout << "CMyWinApp  Destructor  \n"; }

};

class  CMyFrameWnd  :  public  CFrameWnd

{

public:

CMyFrameWnd()   {  cout << "CMyFrameWnd  Constructor  \n"; }

~CMyFrameWnd()   {  cout << "CMyFrameWnd  Destructor  \n"; }

};

MY.CPP源文件:

#include  "MY.h"

CMyWinApp  theApp;

void  main()

{

CWinApp*  pApp  =  AfxGetApp();

}

执行的结果:

CObject  Constructor

CCmdTarget  Constructor

CWinThread  Constructor

CWinApp  Constructor

CMyWinApp  Constructor

CMyWin
12832
App  Destructor

CWinApp  Destructor

CWinThread  Destructor

CCmdTarget  Destructor

CObject Destructor

从程序中可以看到,Frame1并没有new任何对象,反倒是有一个全局对象theApp存在。C++规定,全局对象的建构将比程序进入点(在DOS环境为main,在Windows环境为WinMain)更早。所以theApp的构造函数将更早于main。换句话说,你所看到的执行结果中的那些构造函数输出操作全都是在main函数之前完成的。
在解释一下,因为定义theApp这个全局变量的类为CMyWinApp,而这个类是从一系列基类继承下来的,也就意味着你在声明这个全局变量的时候,就已经依次调用了各个类的构造函数和析构函数,所以才会有上面的输出结果。

main函数调用全局函数AfxGetApp以取得theApp的对象指针。这完全是仿真MFC程序的手法。

2、MFC程序的初始化过程

MFC程序也是一个Window程序,它的内部一定也像第1章所述的一样,有窗口注册操作,有窗口产生操作,有消息循环操作,也有窗口函数。这里我们只交代一个程序流程,这个流程正是任何MFC程序的初始化过程的简化。
以下是Frame2范例程序的类层次及其成员。对于那些“除了构造函数与解构函数之外没有其他成员”的类,我们就不在图中展开它们了。



就如曾在第1章解释过的,InitApplication和InitInstance现在成了MFC的CWinApp的两个虚拟函数。前者负责“每个程序只做一次”的操作,后者负责“每一个例程都得做一次”的操作。
通常,系统会为你注册一些标准的窗口类(当然也就准备好了一些标准的窗口函数),应用程序设计者应该在你的CMyWinApp中改写InitInstance,并在其中把窗口产生出来-----这样你才有机会在标准的窗口类中指定自己的窗口标题和菜单。下面是我们新的main函数:

//MY.CPP
CMyWinApp theApp;
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
}
其中,pApp指向theApp全局对象。这里我们开始看到了虚拟函数的妙用:
pApp->InitApplication()调用的是CWinApp::InitApplication,
pApp->InitInstance() 调用的是CMyWinApp::InitInstance( 因为CMyWinApp改写了它),
pApp->Run()调用的是CWinApp::Run,
好,请注意一下CMyWinApp::InitInstance的操作,以及它所引发的行为:
BOOL CMyWinApp::InitInstance()
{
cout << "CMyWinApp::InitInstance \n";
m_pMainWnd = new CMyFrameWnd; //还记得吗?动态创建时引发CMyFrameWnd::CMyFrameWnd构造函数
return TRUE;
}
CMyFrameWnd::CMyFrameWnd()
{
Create(); //Create是虚拟函数,但是CMyFrameWnd未改写它,所以引发父类的CFrameWnd::Create
}
BOOL CFrameWnd::Create()
{
cout << " CFrameWnd::Create \n";
CreateEx(); //CreateEx是虚拟函数,但CFrameWnd未改写之,所以引发CWnd::CreateEx
return TRUE;
}
BOOL CWnd :: CreateEx()
{
cout << " CWnd:: CreateEx \n";
PreCreateWindow(); //这是一个虚拟函数,CWnd中有定义,CFrameWnd也改写了它。那么你说这里到底是调用CWnd::PreCreateWindow还是CFrameWnd::PreCreateWindow呢?
return TRUE;
}
BOOL CFrameWnd :: PreCreateWindow()
{
cout<<"CFrameWnd::PreCreateWindow \n";
return TRUE;
}
其实,这里调用的是CFrameWnd::PreCreateWindow。这便是第2章的“Object slicing与虚拟函数”一节所说的“虚拟函数的一个极重要的行为方式”。
当然,在这里这些函数什么动作也没做,只是输出一个标识字符串,我们现在主要的目的是让你先熟悉MFC程序的流程。
执行结果:
CWinApp::InitApplication
CMyWinApp::InitInstance
CMyFrameWnd::CMyFrameWnd
CFrameWnd::Create
CWnd::CreateEx
CFrameWnd::PreCreateWindow
CWinApp::Run
CWinThread::Run
Frame2范例程序
MFC.H头文件
#define  BOOL  int
#define  TRUE  1
#define  FALSE  0

#include  <iostream>

using namespace std;

class  CObject      //基类CObject
{
public:
CObject::CObject()  { }  
CObject::~CObject()  { }
};

class  CCmdTarget  :  public  CObject
{
public:
CCmdTarget::CCmdTarget()  {  }  
CCmdTarget::~CCmdTarget()  {  }
};

class  CWinThread  :  public  CCmdTarget
{
public:
CWinThread::CWinThread()  {  }  
CWinThread::~CWinThread()  {  }
virtual  BOOL  InitInstance()
{
cout <<"CWinThread :: InitInstance \n";
return  TRUE;
}
virtual  BOOL  Run()
{
cout <<"CWinThread :: Run \n";
return  TRUE;
}
};

class  CWinApp  :  public  CWinThread
{
public:
CWinApp* m_pCurrentWinApp;
CWnd*  m_pMainWnd;
public:
CWinApp::CWinApp()   { m_pCurrentWinApp = this;}

CWinApp::~CWinApp()  {  }
virtual  BOOL  InitApplication()
{
cout <<"CWinApp :: InitApplication \n";
return  TRUE;
}
virtual  BOOL  InitInstance()
{
cout <<"CWinApp :: InitInstance \n";
return  TRUE;
}
virtual  BOOL  Run()
{
cout <<"CWinApp :: Run \n";
return  CWinThread::Run();
}
};

class  CWnd  :  public  CCmdTarget
{
public:
CWnd::CWnd()  {  }
CWnd::~CWnd()  {  }
virtual  BOOL  Create();
BOOL  CreateEx();
virtual  BOOL  PreCreateWindow();
};

class  CFrameWnd  :  public  CWnd
{
public:
CFrameWnd::CFrameWnd()  {   }
CFrameWnd::~CFrameWnd()  {   }
BOOL  Create();
virtual  BOOL PreCreateWindow();
};

class  CView  :  public  CWnd
{
public:
CView::CView()  {  }
CView::~CView()  {   }

};

//全局函数
CWinApp*  AfxGetApp();
MFC.CPP源文件:
#include "MFC.h"
#include "MY.h"

extern  CMyWinApp  theApp;

CWinApp*  AfxGetApp()
{
return  theApp.m_pCurrentWinApp;
}
 
BOOL  CWnd::Create()
{
cout << "CWnd ::Create \n";
return TRUE;
}

BOOL  CWnd::CreateEx()
{
cout<<"CWnd::CreateEx  \n";
PreCreateWindow();
return  TRUE;
}

BOOL  CWnd::PreCreateWindow()
{
cout << "CWnd ::PreCreateWindow \n";
return TRUE;
}

BOOL  CFrameWnd::Create()
{
cout<<"CFrameWnd::Create \n";
CreateEx();
return  TRUE;
}

BOOL  CFrameWnd::PreCreateWindow()
{
cout<<"CFrameWnd::PreCreateWindow  \n";
return  TRUE;
}

MY.H头文件
#include <iostream>
#include "MFC.h"

class CMyWinApp  :  public  CWinApp
{
public:
CMyWinApp::CMyWinApp()   {   }
CMyWinApp::~CMyWinApp()   {   }
virtual  BOOL  InitInstance();
};

class  CMyFrameWnd  :  public  CFrameWnd
{
public:
CMyFrameWnd();
~CMyFrameWnd()   {  cout << "CMyFrameWnd  Destructor  \n"; }
};
MY.CPP源文件:
#include  "MY.h"

CMyWinApp  theApp;

BOOL CMyWinApp::InitInstance()
{
cout<<"CMyWinApp::InitInstance  \n";
m_pMainWnd  =  new  CMyFrameWnd;
return  TRUE;
}

CMyFrameWnd::CMyFrameWnd()
{
cout<<"CMyFrameWnd::CMyFrameWnd \n";
Create();
}
void  main()
{
CWinApp*  pApp  =  AfxGetApp();


pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
}

程序过程有些繁琐,所以我绘制了一下流程图,从总体上来看整个过程,应该更有注意理解:



下面是在InitInstance()中创建窗口的过程:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: