一、在应用程序类中定义
用MFC生成的工程中都有一个名为CxxxApp的类,它派生于CWinApp类。这个类主要进行程序的初始化,生成文档、视图对象等工作。我们可以把需要全局访问的变量和函数定义为这个类的成员变量和成员函数,就可以实现全局访问了。
从严格意义上讲,这种变量和函数并不是全局的,因为它仍然只是类中的成员,只是由于我们很容易获得CxxxApp类的指针,所以我们可以在文档、视图、对 话框以及各种自定义类中访问到它们,达到与全局变量类似的效果。访问时用函数“AfxGetApp()”获得CxxxApp类的指针,用 “AfxGetApp()->成员”访问变量或函数。
例:
Testh:(应用程序类头文件)
class CTestApp : public CWinApp
{
public:
int x; //全局变量
int f(int y); //全局函数
…………
};
Testcpp:(应用程序类程序文件)
int CTestApp::f(int y) //全局函数定义
{
y++;
return y;
}
定义在CTestApp类中的变量和函数可以在其它类中被访问。比如在视图的某函数中要访问变量x和函数f():
void CTestView::xyz()
{
CTestApp app = (CTestApp )AfxGetApp(); //生成指向应用程序类的指针
app->x = 0; //访问变量x
int z = app->f(1); //访问函数f()
…………
}
这样,变量x和函数f()可以视作为全局的。
用这种方法实现的全局变量和全局函数虽比较简单,但也有缺点,一是访问不太方便,每次都需要获取应用程序类的指针;再就是把一些与应用程序类本身无关的变量和函数放在里面,使这个类看上去怪怪的,破坏了类的封装。
二、用静态变量和静态函数实现
很喜欢API函数的那种调用方法,不论在哪个类中只要用“::API函数”就可以调用了。合理利用静态类型(static)可以实现与此相似的全局变量和全局函数。
静态变量和静态函数有如下性质:
若在一个类中用关键字static声明数据成员,则这个数据成员就只存在一个拷贝,无论该类创建了多少个实例,它始终只存在一个,即使该类的实例一个也没创建,它也存在。
若在一个类中用关键字static声明函数,该函数可以用“类名::函数名”方式访问,无需引用该类的实例,甚至这个类的实例可以不存在。
利用这个性质实现的全局变量和函数使用起来很方便。
值得注意的是,全局变量和全局函数最好集中封装,不要在文档、视图等类内部定义,这样用起来才有全局的感觉。
例:
1、添加一个没有基类的新类,设类名起为CPublic,姑且称之为公用类
单击“Insert”菜单下的“New Class”命令,选择“Class type”为“Generic Class”,在“Name”栏中填入类名“CPublic”,单击“OK”,则新类建立完毕。
2、包含公用类的头文件,使各个类都能访问它
CPublic的头文件应包含在应用程序类的头文件中,这样在其它类中引用CPublic类时就不需要再包含了。
Testh:(应用程序类头文件)
#include "Publich" //包含公用类头文件
class CTestApp : public CWinApp
{
…………
};
3、在公用类中定义全局变量和全局函数,均使用static修饰,静态变量还必须在类外定义和初始化
Publich:(公用类头文件)
class CPublic
{
public:
CPublic();
virtual ~CPublic();
public:
static int x; //全局变量
static int time; //全局变量
static int f(int y); //全局函数
…………
}
在公用类中对静态变量进行初始化和定义函数体:
Publiccpp:(公用类程序文件)
int CPublic::x = 0; //初始化全局变量
int CPublic::time; //定义全局变量
CPublic::CPublic()
{
}
CPublic::~CPublic()
{
}
int CPublic::f(int y) //全局函数,这里不要再加static
{
y++;
return y;
}
4、全局量的使用
使用变量:CPublic::变量名
使用函数:CPublic::函数()
如在视图的某函数中访问变量x和函数f():
void CTestView::xyz()
{
CPublic::x = 0; //访问变量x
CPublic::time = CPublic::f(1); //访问函数f()
…………
}
在其它类中访问x、time和f()的方法与此相同。
5、几点注意:
① 由于静态量可独立于类存在,不需要生成CPublic类的实例。
② 静态数据成员的定义和初始化必须在类外进行,如例中x的初始化;变量time虽然没有初始化,但也必须在类外进行定义。由于没有生成CPublic类的实例,所以它的构造函数和析构函数都不会被执行,在里面做什么工作都没有什么意义。
③ 如果静态函数需要访问CPublic类内的变量,这些变量也必须为静态的。因为非静态量在不生成实例时都不会存在。 如:
class CPublic
{
public:
int x; //内部变量
static int f(int y) //全局函数
{
x++;
return x;
};
…………
};
这里x虽为类内成员,但如果不生成CPublic类的实例,就会出现函数f()存在,而变量x不存在的问题。
总之,用没有实例的类管理全局量是一个不错的选择,它具有集中管理,使用方便的好处。当然,除非特别必要,全局量还是少用为好,一个好的编程者决不会随意滥用全局量的,一个封装做得不好的程序,在修改维护时会让你吃足苦头。
ps:直接在stdafxh中加入#include"afxdbh"。然后用Cdatabase db在该文件中定义就可以当全局变量使用了。不过不知道好不好,仅仅能用而已。有句话说的好,先要跑起来,再要求跑的快。呵呵,优化的前提"Get it to work,then make it fast"
也可以跟theApp定义在一块,在要引用全局变量的文件前面加extern声明;
ps2:
definition is similar to the first method,but how to use it is different
在CTestApp中定义变量:
CString g_sUser;//定义全局
在要引用的类中如此:
extern CTestApp theApp;//加入 这句在CPP文件的构造函数前
在引用时:
if( theAppm_gsUser == "") ;//这样引用
子线程没有main函数入口的说法,但在部分工程模式下,允许命名子线程函数为main
MFC程序本身不是多线程
任何win32下的C++程序都支持用户自定义多线程,MFC也不例外,就是这个关系。
都是什么回答啊
楼主 你没有了解MFC的运行机制就去看他写他所以你先要了解他的机制 已经各个CPP H都是什么
下面我就给你说下
在MFC程序中,我们并不经常直接调用Windows API,而是从MFC类创建对象并调用属于这些对象的成员函数也就是说MFC封装了Windows API 你说你喜欢C++而MFC换一种说法就是一个用C++写的一个函数库 然后你来调用 只不过这个类不是你写的
MFC提供数百个类,最重要的、也是编写任何VC++应用程序都必不可少的两个类CWinApp和CFrameWnd,这两个类是编写复杂庞大应用程序的基石。
1>封装特性:构成MFC框架的是MFC类库而MFC类库又是C++的一个类库。这些类封装WIN32应用程序编程接口,OLE(Object Link Embed 对象链接嵌入)特性,ODBC和DAO数据访问的功能。
2>继承特性:MFC抽象出了众多类的共同特性,并设计出一些基类作为实现其他类的基础,这些类中最重要的类是CObject类和CCmdTarget类,程序员可以从适当的MFC类中派生出自己的类,实现特定的功能达到编程的目的。
3>虚拟和消息映射:MFC是以C++为基础,当然支持虚函数,但作为一个编程框架必须要解决的是效率问题:如果MFC仅仅通过虚函数来支持动态约束必然会产生大量的虚函数表这样编程框架过于臃肿而且消耗更多的内存。但是MFC建立了消息映射机制这样降低了内存的使用却大大提高了效率
消息映射是一个将消息和成员函数相互关联的表,当应用程序的框架窗口接收到一个消息时,MFC将搜索该窗口的消息映射,如果存在一个处理消息的处理程序,那么就调用该处理程序
它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V表),节省内存。
MFC消息映射机制:
将消息与消息处理函数联系起来,形成一一对应的机制。
消息映射宏
声明: DECLARE_MESSAGE_MAP
定义:
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_CONTROL
ON_MESSAGE
END_MESSAGE_MAP
MFC主要组成部分:类、宏和全局函数。
类是MFC中最主要的内容。MFC类是以层次结构方式组织起来的。MFC中的类分成两部分,除了一些辅助类,大多数的MFC类是直接或间接从根类CObject派生而来。
MFC宏主要功能:消息映射、运行时对象类型服务、诊断服务、异常处理。
MFC约定:全局函数以“Afx”为前缀,全局变量以“afx”为前缀
MFC类的层次关系
CObject项目类)->CCmdTarget(消息响应类)->
{
CWinThread(线程类)->CWinApp(Window应用程序类)
CDocument(文档类)
CWnd(窗体类)->[
CFrameWnd(框架类)
CView(视图类)
]
}
CObject类由于MFC中大部分类是从CObject类继承而来的,CObject类描述了几乎所有的MFC类的一些公共特性,CObject类为程序员提供了对象诊断、运行时类型识别和序列化等功能。
CCmdTarget类由CObject类直接派生而来,它负责将消息发送到能够响应这些消息的对象。它是所有能进行消息映射的MFC类的基类。
CWinApp类在任何MFC应用程序中有且仅有一个CWinApp派生类的对象,它代表了程序中运行的主线程,也代表了应用程序本身。 CWinApp类取代了WinMain()主函数在SDK应用程序中的地位。传统SDK应用程序WinMain()函数完成的工作。现在由类CWinApp的InitApplication(),InitInstance()和Run()三个成员函数承担。
CWnd类由CCmdTarget类直接派生而来,该类及其派生类的实例是一个窗口。CWnd类代表了MFC中最基本的GUI对象,它是一个功能最完善、成员函数最多的MFC类。
CFrameWnd类是CWnd类的派生类,主要用来掌管一个窗口,它取代了SDK应用程序中窗口函数WndProc()的地位。CFrameWnd类的对象是一个框架窗口,包括边框、标题栏、菜单、最大化按钮、最小化按钮和一个激活的视图。
CDocument类在应用程序中作为用户文档类的基类,它代表了用户存储或打开的一个文件。
CView类是MFC中一个很基本的类,它作为其它MFC视图类和用户视图派生类的基类。
从API编程到MFC编程的过渡:
WinMain()
{ 初始化WNDCLASS
注册窗体结构
创建窗口 ->>>>>>>>应用程序类CWinApp
显示窗口
消息循环
}
WndProc()
{ switch(…)
->>>>>>>>>框架窗口类CFrameWnd
}
MFC Object和Windows Object的对应关系:
描述 Windows句柄 MFC Object
窗口 HWND CWnd
设备上下文 HDC CDC
菜单 HMENU CMenu
笔 HPEN CPen
刷子 HBRUSH CBrush
字体 HFONT CFont
位图 HBITMAP CBitmap
套接字 SOCKET CSocket
三、手工创建一个MFC应用程序:
注意:创建MFC程序,要创建一个Win32空项目,并要选择项目属性中的”在共享DLL文件中使用MFC,然后新建我们的文件
例子:在”helloh”头文件中添写如下代码:
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();//虚函数
};
class CMainWindow:public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP();//声明消息映射
};
在”hellocpp”源文件中添写如下代码:
#include <afxwinh>
#include “helloh"
CMyApp myApp;
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP() //消息映射
CMainWindow::CMainWindow() //构造函数初始化
{
Create(NULL,“我的第一个MFC应用程序”);//创建窗体
}
void CMainWindow::OnPaint()
{ CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
dcDrawText("Hello MFC",-1,&rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
CWinApp是应用程序类,在MFC应用程序中必须从这个类派生出一个类,该派生类是MFC应用程序的入口
必须定义这个派生类的对象,并且只能有一个这个对象代表整个应用程序。
成员函数:InitInstance()
功能:初始化应用程序实例和窗口实例,
虚函数CWinApp::InitInstance必须在派生类中重写。在InitInstance函数中,编写初始化代码,如:
创建一个窗口
显示一个窗口
CFrameWnd类
作用:为应用程序提供一个窗口,同时实现消息处理功能。
成员函数: Create()
功能:创建窗体,将之赋于CFrameWnd对象上。
BOOL Create(窗口类型, 窗口标题,显示风格,显示区域,符窗口句柄,菜单,扩展显示风格,上下文对象)共有8个参数,前两个必须给出,后6个可以默认。
MFC应用程序的核心就是基于CWinApp类的应用程序对象,CWinApp提供了消息循环来检索消息并将消息调度给应用程序的窗口我们在编写MFC应用程序时,要包含afxwinh,
一个MFC应用程序可以有且仅有一个应用程序对象,对象必须声明为在全局范围内有效(也就是全局对象),以便它在程序开始时即在内存中被实例化
我们的Hello MFC的应用程序类被命名为CMyApp,它在hellocpp中用如下语句进行了实例化:
CMyApp myApp;
CMyApp的类声明在helloh中代码如下:
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
CMyApp没有声明任何的数据成员,只是重写了一个从CWinApp类中继承来的函数,在应用程序的生存期内InitInstance的调用比较早,是在应用程序开始运行以后而窗口创建之前,除非InitIstance创建一个窗口,否则应用程序是不会有窗口,这正是为什么即使最小的MFC应用程序也必须从CWinApp派生出一个类并重写CWinApp::InitIstance的原因
InitInstance函数:CWinApp::InitInstance是一个虚函数,其默认 *** 作仅包含一条语句:return TRUE;
InitInstance是用来执行程序每次开始时都需要进行的初始化工作最好的地方
在hellocpp中,CMyApp的InitInstance通过实例化hello的CMainWindow类来创建hello窗口,语句:
m_pMainWnd = new CMainWindow;
构造了一个CMainWindow对象指针,并将其地址复制到了应用程序对象的m_pMainWnd数据成员中,窗口创建以后,InitInstance就会通过CMainWindow指针调用ShowWindow和UpdateWindow函数显示它:
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
ShowWindow和UpdateWindow是所有窗口对象共用的CWnd成员函数其中包括CFrameWnd类的对象,CMainWindow就是从CFrameWnd派生出来的
要从MFC程序调用一个常规的Windows API函数,需要在函数名称前添加一个全局运算符:: 例如:::UpdateWindow();
通过生成窗口对象并调用其Create函数,MFC应用程序可以创建一个窗口,在CMyApp::InitInstance中,hello创建了一个CMainWindow对象,CMainWindow的构造函数生成在屏幕上看到的窗口:
Create(NULL,”我的第一个MFC应用程序”);
CPaintDC dc(this);
MFC的CPaintDC类是从MFC的CDC类派生的,CDC类封装了Windows设备环境,以及包含了绘制到屏幕、打印机和其他设备的几十个成员函数
在MFC中如何处理消息呢
在SDK中我们利用的是消息循环和窗口过程函数对消息进行消息处理
在MFC中我们用的是消息映射机制
下面是将消息映射添加到一个类中需要做的全部工作
1>通过将DECLARE_MESSAGE_MAP语句添加到类声明中,声明消息映射
2>通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的调用之间处理消息
3>添加成员函数来处理消息
1、构造CWinApp派生类的对象
2、系统调用WinMain()
3、WinMain调用InitInstance,在该函数中创建CFrameWnd派生类对象,调用Create函数创建窗口、调用ShowWindow函数显示窗口。
4、之后内部机制调用Run,接受用户的消息,并将消息导向默认的处理函数。当接收到WM_QUIT消息时,Run内部调用ExitInstance,退出程序。
MFC采用消息映射(Message Map)机制取代C/C++语言中的switch-case结构来处理消息。
消息映射:在MFC中把消息处理函数和它所要处理的特定的消息连接起来的一种机制。
它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V表),节省内存。
MFC消息映射机制包括一组消息映射宏。一条消息映射宏把一个Windows消息和其消息处理函数联结起来。
MFC应用程序框架提供了消息映射功能。
在类的实现源文件中用BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏来定义消息映射。
在类定义的结尾用DECLARE_MESSAGE_MAP()宏来声明使用消息映射。
Hello的CmainWindow类只处理一种消息类型—WM_PAINT,因此其消息映射的实现如下所示:
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd);
ON_WM_PAINT()
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP开始了消息映射,并标识了消息映射所属的类和该类的基类
END_MESSAGE_MAP()结束消息映射
ON_WM_PAINT()在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间,称做消息条目,在MFC为100多种Window消息提供了宏
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
afx_msg 醒目地暗示OnPaint是一个消息处理程序,
DECLARE_MESSAGE_MAP()声明消息映射
MFC把消息主要分为三大类:
(1)、标准Windows消息(WM_XXX)
使用宏:ON_WM_XXX() 特点:有默认的消息处理函数
(2)、命令消息:(WM_COMMAND)
来自于菜单、工具条、按钮等的消息
使用宏: ON_COMMAND(命令按钮标识符ID,消息处理函数)
特点:由用户指定消息处理函数
3、”Notification消息” (通知消息) 由控件产生:
BOOL 布尔值,取值为TRUE或者FALSE
BSTR 32为字符指针
BYTE 8位整数无符号的
COLORREF 32位数值代表一个颜色值
DWORD 32位整数无符号的
LONG 32位整数带符号的
LPCTSTR 32位指针,指向一个常字符串
LPVOID 32位指针,指向一个为指定类型的数据
MFC特有的数据类型:
1>POSITION :一个数值,代表数组或者链表中元素的位置,在MFC中常用于数据处理类
2>LPRECT:32位指针,指向一个不变的矩形区域结构
这是我针对你的问题整理的一些资料 很多 我想删减一些 但我觉得这些都对你很重要
另外,团IDC网上有许多产品团购,便宜有口碑
你先在菜单中调出属性窗口(视图-->其他窗口-->属性窗口),然后点击到该类的头文件,将光标定位到类的头文件里面,你就可以在属性窗口中看见相应的东东了,包括虚函数,消息响应函数等等,自己随便添加吧。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)