孙鑫VC++LESSON3:MFC框架程序剖析

  MFC是微软提供给我们的基础类库,是一套面向对象的函数库,以类的方式提供给我们使用,利用这些类可以有效地完成基于Windows的应用程序开发。
  对于在main函数之前定义的全局变量,他在进入入口函数之前就分配了内存,如果是类的对象就调用它的构造函数。
  CTestApp 类定义的theApp全局变量->CTestApp 类的构造函数->appmodul.pp中的WinMain函数。
  生成的MFC项目里面并没有WinMain入口函数,而是在编译的时候再链接到appmodul.pp中的WinMain函数。
  WinMain函数在C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc
  那么这个theApp全局对象有什么作用?这个theApp是个应用程序对象,每一个MFC程序当中有且仅有一个从CWinApp中派生出来的类,也有且仅有一个从这个应用程序类实例化出来的对象,他就表示了我们应用程序本身。在第一堂课写的Win32SDK程序当中,我们表示一个应用程序实际上是从WinMain入口函数通过一个实例号来表示的,基于MFC的是通过产生一个应用程序类的对象来唯一表示的。这个全局变量再调用构造函数时,会先调用其父类CWinApp的构造函数(微软提供),也就相应地完成了一些初始化的工作,这样子类和基类就联系起来了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  因为这个基类带参数的构造函数,这个参数有缺省值,所以子类构造函数可以不用显示的调用基类构造函数
在这里插入图片描述
  CWinApp函数定义在appcore.cpp文件里
  C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc
  这个this指针指向派生类的对象。
https://blog.csdn.net/qq_45662588/article/details/116790909https://blog.csdn.net/qq_45662588/article/details/116790909
在这里插入图片描述
基类:

class Base{
public:
	Base()
	{
		cout << "Base this : " << typeid(this).name() << endl;
		cout << "Base this =" << this << endl;
	}
	void fun()
	{
		cout << "fun this : " << typeid(this).name() << endl;
		cout << "fun this =" << this << endl;
	}
};


派生类

class Derived : public Base{
public:
	Derived(){
		cout << "Derived this : " << typeid(this).name() << endl;
		cout << "Derived this = " << this << endl;
	}
};


main函数

int main(int argc, char* argv[])
{
	std::cout << "*****************Derived**********************\n";
	Derived dev;
	dev.fun();
	std::cout << "\n*****************Base**********************\n";
	Base base;
	base.fun();
	system("pause");
	return 0;
}


结果为:
在这里插入图片描述
在这里插入图片描述

#include <iostream>
using namespace std;

class CWinApp;
CWinApp *m_pCurrentWinApp;

class CWinApp{
public:

	CWinApp()
	{
		cout << "CWinApp this : " << typeid(this).name() << endl;
		cout << "CWinApp this =" << this << endl;
		m_pCurrentWinApp = this;
		cout << endl;
	}
	virtual void fun()
	{
		cout << "CWinApp fun this : " << typeid(this).name() << endl;
		cout << "CWinApp fun this =" << this << endl;
		cout << endl;
	}
};

class CMyWinApp : public CWinApp{
public:
	CMyWinApp() {
		cout << "CMyWinApp this : " << typeid(this).name() << endl;
		cout << "CMyWinApp this = " << this << endl;
		cout << endl;
	}

	virtual void fun()
	{
		cout << "CMyWinApp fun this : " << typeid(this).name() << endl;
		cout << "CMyWinApp fun this =" << this << endl;
		cout << endl;
	}
};

/*这是个全局变量,因此会调用CMyWinApp构造函数,由于基类为CWinApp,所以先调用CWinApp构造函数,
这样,通过m_pCurrentWinApp = this,m_pCurrentWinApp就指向了CMyWinApp对象。
(也就是说,m_pCurrentWinApp是一个基类指针,指向派生类对象,调用虚函数时,就会调用派生类的对应虚函数。)*/
CMyWinApp theApp;

int main()
{
	std::cout << "m_pCurrentWinApp=" << m_pCurrentWinApp << endl;;
	m_pCurrentWinApp->fun();

	system("pause");
	return 0;
}


在这里插入图片描述
  接下来是WinMain函数,他是用AfxWinMain这个函数完成WinMain功能,带afx前缀的函数是属于应用程序框架的函数,应用程序框架的函数实际上是辅助我们生成这个应用程序框架模型,这个框架模型把很多类与类之间有机的集成提供给我们,我们可以根据它所设计的方案来设计我们自己的应用程序application framwarld
在这里插入图片描述
AfxWinMain在文件WinMain.cpp里面
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc
在这里插入图片描述
此处这个AfxGetApp()函数获取一个CWinApp的指针,他所代表的含义同上所述的this指针,指向子类对象的指针。
在这里插入图片描述
  这里pApp调用了三个函数在这三个函数当中就完成了做一个应用程序所需要的几个步骤:设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环、窗口过程函数。这里InitApplication主要是MFC内部管理调用的一个函数。
下面pThread调用了InitInstasce(),pThread这个指针同样是指向子类的对象的指针,CWinApp是从CWinThread派生出来的。
在这里插入图片描述
  可以看到InitInstasce是虚函数,根据动态性原理,pThread调用的InitInstasce(),是子类的InitInstasce
在这里插入图片描述
  接下来,又调用了RUN方法,实际上是完成了消息循环.
  设计窗口类:在MFC中他预先给我们定义好了几种缺省的窗口类
  注册窗口类:函数AfxEndDeferRegisterClass完成了注册窗口类,他在wincore.cpp中。函数里面很多if根据你提供的类名进行注册

框架类
  框架类
子窗口
在这里插入图片描述
在这里插入图片描述
  判断这个类是否注册,没有注册的话进行注册,然后第二条是把这个类名赋给lpszclass
在这里插入图片描述
  定义这个creatstruct结构体是为了能够让我们在生成窗口前有机会进行修改外观,通过子类修改基类的参数
在这里插入图片描述
  显示窗口
  更新窗口
  消息循环:在这里插入图片描述
在这里插入图片描述
  translatemessage将WMKEY_UP和WMKEY_DOWN组合成WMKEY_CHAR消息,然后dispatchmessage将消息路由给操作系统,然后由操作系统交给窗口过程函数进行处理。
  流程:全局-》构造函数-》-》winmain-》initinstance(完成初始化的工作、完成窗口类的注册、产生、显示和更新)-》pumpmessage进入消息循环(取出一条消息路由给操作系统,然后由操作系统交给窗口过程函数进行处理),然后在此循环。
在这里插入图片描述
  在这个地方他设置的窗口过程函数选择的是一个缺省的窗口过程函数,实际上在MFC当中所有的消息循环路由给操作系统的消息并不都是交给缺省的窗口过程函数处理的,他在这个里面做了个转换,采用了一种消息映射的技术,由消息响应函数来进行处理。

总结

  第一步:构建全局对象(通过构建这个全局变量来启动这个应用程序,正是由于这个全局对象产生了,this指针才能指向这个对象,如果没有这个全局变量程序的编译不会出错但是运行出错。当我们定义这个全局对象时会调用构造函数,由于构造子类先构造父类,所以CWinApp的构造函数就被调用,在CWinApp的构造函数当中,完成了一些应用程序初始化的一些工作,同时将我们子类的指针保存起来)
在这里插入图片描述
  第二步:指针保存起来之后进入到WinMain函数,在AfxWinMain函数当中就可以获取到子类的指针,利用子类的指针,我们可以调用一个虚拟的函数,利用多态性的原理,相应的就会调用到子类里的函数,也就是InitInstance()函数。这个窗口产生来回进行了好几个步骤
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  第三步:在InitInstance这个函数中,完成初始化的工作、完成窗口类的注册、创建、显示和更新
注册窗口类
创建窗口
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  第三步:消息循环。在这个地方他设置的窗口过程函数选择的是一个缺省的窗口过程函数,实际上在MFC当中所有的消息循环路由给操作系统的消息并不都是交给缺省的窗口过程函数处理的,他在这个里面做了个转换,采用了一种消息映射的技术,由消息响应函数来进行处理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


在这里插入图片描述
  这个CMainFrame和CTestView类都是窗口类(从CWnd类派生出来的),CMainFrame可以理解为CTestView窗口的副窗口,他是覆盖在框架窗口之上的。CTestApp表示的应用程序类,所产生对象是应用程序对象,在MFC程序当中,有且只能有一个应用程序对象。这个CTestDoc类实际是从CDocument类(文档类)派生出来的。文档视类结构:数据的存储、加载都由文档类完成,数据的显式修改都由View类完成,这样就把数据本身和数据的处理、显示分开了。

在这里插入图片描述
  那么,是怎么实现CMainFrame、CTestDoc、CTestView三个结合起来呢?
  在InitInstance()中定义了一个单文档模板指针,这个指针用了一个new,然后将文档、框架类、View类有机的组合在一起了,通过一个单文档的模板组合在一起了。然后利用AddDocTemplate函数将这个单文档模板增加到文档模板当中。
在这里插入图片描述
  这个CAboutDlg表示了一个对话框的类,这个类可有可无,点帮助弹出来一个窗口,它本身也是一个窗口类,从CWnd派生出来
在这里插入图片描述
  窗口类、窗口类的对象、窗口之间是什么关系?
  对象和窗口的唯一联系就是:c++对象内部定义了一个窗口的句柄,这个句柄保存了和他相关的窗口的句柄,窗口销毁,他的对象销不销毁要看它的生命周期结没结束。
  新建-Win32应用程序-空项目
在这里插入图片描述
  ::ShowWincow,这里::前不加东西表示这是一个全局函数,是一个Win32平台SDK的API函数,如果在一个类当中,你想调用的函数是平台SDK的函数,但是跟你在类中定义的函数重复了,编译时就会出错,要加作用域解析符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值