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

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

如何仿真呢?我们在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


CMyWinApp  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()中创建窗口的过程:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值