MFC 编程:Windows 桌面应用程序开发框架

目录

一.概述

[二.MFC 与 Win32 的关系](#二.MFC 与 Win32 的关系)

[三.CObject 类](#三.CObject 类)

[1.CObject 类的主要功能](#1.CObject 类的主要功能)

[2.CObject 类的派生类](#2.CObject 类的派生类)

[3.CObject 类成员函数](#3.CObject 类成员函数)

4.内存管理

对象的创建

对象的销毁

引用计数

复制对象

5.序列化

序列化的概念

[CObject 类的序列化功能](#CObject 类的序列化功能)

序列化示例

6.运行时类型信息

运行时类型信息的概念

[CObject 类的 RTTI 功能](#CObject 类的 RTTI 功能)

[RTTI 示例](#RTTI 示例)

[四.MFC 消息映射的实现](#四.MFC 消息映射的实现)

1.消息映射宏

消息映射宏概述

消息映射宏语法

消息映射宏示例

2.消息处理函数

3.消息处理过程

消息处理过程示例

消息处理过程的要点

[五.MFC 对象的创建](#五.MFC 对象的创建)

1.创建对象

2.初始化对象

3.使用对象

4.销毁对象

六.应用程序的退出

1.处理未保存的数据

2.释放资源

[3.注销 MFC DLL](#3.注销 MFC DLL)

4.退出应用程序

总结


一.概述

MFC(Microsoft Foundation Class)是 Microsoft 公司提供的一套 C++ 类库,用于在 Windows 平台上开发桌面应用程序。MFC 提供了一套丰富的类和函数,抽象了 Windows API,简化了 Windows 应用程序的开发过程。MFC 广泛应用于各种 Windows 桌面应用程序中,包括办公软件、图像处理软件、游戏等。

二.MFC 与 Win32 的关系

Win32 API(Windows API)是 Microsoft 提供的底层 API,用于在 Windows 平台上开发应用程序。Win32 API 提供了对 Windows 操作系统功能的直接访问,但使用起来较为复杂和繁琐。MFC 则是构建在 Win32 API 之上的一层封装,它提供了一套面向对象的类,简化了 Windows 应用程序的开发。MFC 抽象了 Win32 API 的细节,为程序员提供了一套更高级别的接口,使他们能够更容易地实现复杂的 Windows 应用程序。

MFC 与 Win32 的主要区别如下:

  • 抽象层次: Win32 API 是面向过程的,而 MFC 是面向对象的。这意味着 MFC 抽象了 Win32 API 的细节,为程序员提供了一套更易于使用的类和对象。
  • 开发效率: 使用 Win32 API 开发应用程序需要编写更多的代码,而使用 MFC 可以显著提高开发效率。MFC 提供了大量的类和函数,可以帮助程序员快速完成常见任务。
  • 代码可维护性: 使用 MFC 开发的应用程序代码通常比使用 Win32 API 开发的代码更易于理解和维护。MFC 的类和对象具有良好的封装性,可以提高代码的可重用性和可维护性。

MFC 与 Win32 的优缺点比较:

特性 Win32 API MFC
抽象层次 面向过程 面向对象
开发效率 较低 较高
代码可维护性 较差 较好
代码执行效率 较高 较低
系统兼容性 更好 较差

三.CObject 类

CObject 类是 MFC 类库中的基类,所有 MFC 类都直接或间接地派生自 CObject。CObject 类提供了 MFC 类库的基本功能,包括内存管理、序列化、运行时类型信息等。CObject 类还定义了 MFC 类库的公共接口,如创建对象、销毁对象、访问对象属性等。

1.CObject 类的主要功能

  • 内存管理:CObject 类提供了内存管理功能,包括分配和释放内存、跟踪内存泄漏等。
  • 序列化:CObject 类支持序列化,即可以将对象的状态保存到文件中或流中,以便以后恢复。
  • 运行时类型信息:CObject 类支持运行时类型信息 (RTTI),即可以获取对象的类型信息,以便进行动态类型转换等操作。
  • 公共接口:CObject 类定义了 MFC 类库的公共接口,如创建对象、销毁对象、访问对象属性等。

2.CObject 类的派生类

所有 MFC 类都直接或间接地派生自 CObject。派生自 CObject 类的类可以继承 CObject 类的所有功能,并可以扩展 CObject 类的功能。

MFC 类库提供了大量的派生自 CObject 的类,这些类可以用于实现各种各样的 Windows 应用程序功能。例如,CDC 类用于实现设备上下文,CWnd 类用于实现窗口,CDocument 类用于实现文档等。

3.CObject 类成员函数

CObject 类定义了大量的成员函数,用于实现 CObject 类的功能。以下是一些常用的 CObject 类成员函数:

创建对象new 运算符用于创建 CObject 类的对象。例如,以下代码创建了一个 CDC 对象:

cpp 复制代码
CDC* pDC = new CDC;

销毁对象delete 运算符用于销毁 CObject 类的对象。例如,以下代码销毁了 pDC 对象:

cpp 复制代码
delete pDC;

访问对象属性:CObject 类定义了大量的属性,用于访问对象的属性值。例如,以下代码获取 pDC 对象的设备句柄:

cpp 复制代码
HWND hWnd = pDC->GetSafeHwnd();

4.内存管理

CObject 类提供了内存管理功能,包括对象的创建、销毁和复制。MFC 类库使用引用计数来管理对象的内存,当对象的引用计数变为 0 时,对象会被自动销毁。

对象的创建

CObject 类的对象可以使用 new 运算符来创建。例如,以下代码创建了一个 CDC 对象:

cpp 复制代码
CDC* pDC = new CDC;
对象的销毁

CObject 类的对象可以使用 delete 运算符来销毁。例如,以下代码销毁了 pDC 对象:

cpp 复制代码
delete pDC;
引用计数

MFC 类库使用引用计数来管理对象的内存。每个对象都有一个引用计数,表示指向该对象的引用数。当对象的引用计数变为 0 时,对象会被自动销毁。

例如,以下代码创建了两个指向 CDC 对象 pDC 的引用:

cpp 复制代码
CDC* pDC = new CDC;
CDC* pDC2 = pDC;

此时,pDC 对象的引用计数为 2。

以下代码将 pDC2 变量设置为 NULL:

cpp 复制代码
pDC2 = NULL;

此时,pDC 对象的引用计数为 1。

以下代码销毁 pDC 对象:

cpp 复制代码
delete pDC;

此时,pDC 对象的引用计数变为 0,对象会被自动销毁。

复制对象

CObject 类的对象可以使用 Clone() 函数来复制。例如,以下代码复制了 pDC 对象:

cpp 复制代码
CDC* pDC3 = pDC->Clone();

5.序列化

CObject 类提供了序列化功能,允许对象将自己的数据保存到磁盘文件中,或从磁盘文件中加载数据。序列化使对象能够在不同进程或不同计算机之间传输数据。

序列化的概念

序列化是一种将对象的状态保存到存储介质(例如文件、内存或流)中的过程,以便以后可以恢复该状态。反序列化是指将存储介质中的数据加载到对象中的过程。

序列化通常用于以下目的:

  • 持久化数据:将对象的状态保存到磁盘文件中,以便以后可以恢复该状态。
  • 数据传输:将对象的状态传输到另一个进程或另一台计算机。
  • 存档和恢复:将对象的备份保存到磁盘文件中,以便在发生故障时可以恢复该对象。
CObject 类的序列化功能

CObject 类提供了 Serialize() 函数和 IsSerializable() 函数来支持序列化。

  • Serialize() 函数用于将对象的状态保存到存储介质中或从存储介质中加载数据。
  • IsSerializable() 函数用于判断对象是否可序列化。

Serialize() 函数的原型如下:

cpp 复制代码
void Serialize(CArchive& ar);

其中,ar 是一个 CArchive 对象,用于指定存储介质。

Serialize() 函数会依次调用对象的各个成员函数的 Serialize() 函数来序列化对象的成员变量。

IsSerializable() 函数的原型如下:

cpp 复制代码
BOOL IsSerializable();

如果对象可序列化,则该函数返回 TRUE;否则,返回 FALSE。

序列化示例

以下代码演示了如何序列化一个 CDC 对象:

cpp 复制代码
CDC* pDC = new CDC;

CFile file("test.dat", CFile::modeCreate | CFile::modeWrite);
CArchive ar(&file, CArchive::archiveNormal);

pDC->Serialize(&ar);

ar.Close();
file.Close();

delete pDC;

以上代码将 pDC 对象的状态保存到 test.dat 文件中。

以下代码演示了如何从 test.dat 文件中加载一个 CDC 对象:

cpp 复制代码
CFile file("test.dat", CFile::modeRead);
CArchive ar(&file, CArchive::archiveNormal);

CDC* pDC2 = new CDC;
pDC2->Serialize(&ar);

ar.Close();
file.Close();

6.运行时类型信息

CObject 类提供了运行时类型信息 (RTTI) 功能,允许对象在运行时获取自己的类型信息,如类名、属性名等。运行时类型信息使对象能够动态地处理数据,实现灵活的编程。

运行时类型信息的概念

运行时类型信息 (RTTI) 是一种在运行时获取对象类型信息的技术。RTTI 使程序能够在不知道对象具体类型的情况下,对对象进行操作。

RTTI 通常用于以下目的:

  • 动态类型转换:将对象转换为另一种类型。
  • 类型检查:检查对象是否属于某种类型。
  • 获取对象信息:获取对象的类名、属性名等信息。
CObject 类的 RTTI 功能

CObject 类提供了以下 RTTI 函数:

  • IsKindOf() 函数:用于判断对象是否属于某种类型。
  • GetType() 函数:用于获取对象的类型信息。
  • GetRuntimeClass() 函数:用于获取对象的运行时类。

IsKindOf() 函数的原型如下:

cpp 复制代码
BOOL IsKindOf(const CRuntimeClass* pClass);

其中,pClass 是要判断的类的运行时类。

如果对象属于 pClass 类或其派生类,则该函数返回 TRUE;否则,返回 FALSE。

GetType() 函数的原型如下:

cpp 复制代码
CRuntimeClass* GetType();

该函数返回对象的运行时类。

GetRuntimeClass() 函数的原型如下:

cpp 复制代码
const CRuntimeClass* GetRuntimeClass();
RTTI 示例

以下代码演示了如何使用 IsKindOf() 函数来判断对象是否属于某种类型:

cpp 复制代码
CDC* pDC = new CDC;

if (pDC->IsKindOf(RUNTIME_CLASS(CDC)))
{
    // pDC 是一个 CDC 对象
}
else
{
    // pDC 不是一个 CDC 对象
}

delete pDC;

以上代码判断 pDC 对象是否属于 CDC 类。如果是,则执行 if 语句块;否则,执行 else 语句块。

以下代码演示了如何使用 GetType() 函数来获取对象的类型信息:

cpp 复制代码
CDC* pDC = new CDC;

CRuntimeClass* pClass = pDC->GetType();

CString strClassName = pClass->GetClassName();

delete pDC;

四.MFC 消息映射的实现

MFC 消息映射是 MFC 框架中一个重要的机制,它实现了 Windows 消息处理机制。MFC 框架将 Windows 消息映射到 MFC 类的成员函数,从而实现了对 Windows 消息的处理。MFC 消息映射机制简化了 Windows 消息处理过程,使程序员能够更容易地实现复杂的用户界面和事件处理。

1.消息映射宏

MFC 提供了消息映射宏,如 BEGIN_MESSAGE_MAPON_COMMANDEND_MESSAGE_MAP 等,程序员可以使用这些宏来定义 MFC 类的成员函数与 Windows 消息之间的映射关系。消息映射宏使程序员能够方便地处理 Windows 消息,而无需直接使用 Windows API 函数。

消息映射宏概述
  • BEGIN_MESSAGE_MAP 宏用于声明消息映射的开始。
  • ON_COMMAND 宏用于将命令消息映射到成员函数。
  • END_MESSAGE_MAP 宏用于声明消息映射的结束。
消息映射宏语法
cpp 复制代码
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
    ON_COMMAND(ID_MYCOMMAND, OnMyCommand)
    ON_WM_CREATE(&CMyClass::OnCreate)
END_MESSAGE_MAP()
  • CMyClass 是要映射消息的类名。
  • CWndCMyClass 类的基类名。
  • ID_MYCOMMAND 是要映射的命令消息 ID。
  • OnMyCommand 是处理 ID_MYCOMMAND 消息的成员函数名。
  • OnCreate 是处理 WM_CREATE 消息的成员函数名。
消息映射宏示例

以下代码演示了如何使用消息映射宏将命令消息 ID_MYCOMMAND 映射到成员函数 OnMyCommand

cpp 复制代码
class CMyClass : public CWnd
{
public:
    BEGIN_MESSAGE_MAP(CMyClass, CWnd)
        ON_COMMAND(ID_MYCOMMAND, OnMyCommand)
    END_MESSAGE_MAP()

    void OnMyCommand();
};

void CMyClass::OnMyCommand()
{
    // 处理 ID_MYCOMMAND 消息
}

2.消息处理函数

消息处理函数是 MFC 框架中用于处理 Windows 消息的函数。MFC 框架提供了默认的消息处理函数,如 CWnd::WindowProc,该函数负责将 Windows 消息路由到相应的成员函数。程序员可以通过重写 CWnd::WindowProc 函数来处理自定义消息。

以下代码演示了如何重写 CWnd::WindowProc 函数来处理自定义消息 WM_MYMESSAGE

cpp 复制代码
class CMyClass : public CWnd
{
public:
    BEGIN_MESSAGE_MAP(CMyClass, CWnd)
        ON_WM_MYMESSAGE(&CMyClass::OnMyMessage)
    END_MESSAGE_MAP()

    LRESULT OnMyMessage(UINT nMessage, WPARAM wParam, LPARAM lParam);
};

LRESULT CMyClass::OnMyMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
{
    // 处理 WM_MYMESSAGE 消息
    return CWnd::OnMyMessage(nMessage, wParam, lParam);
}

3.消息处理过程

MFC 消息处理过程包括以下几个步骤:

  1. Windows 操作系统将 Windows 消息发送给 MFC 应用程序

Windows 操作系统会将各种消息发送给应用程序,例如鼠标点击、键盘按下、窗口创建等。这些消息都被封装在 Windows 消息结构体中。

  1. MFC 框架将消息路由到相应的 MFC 类

MFC 应用程序通常有一个主窗口,负责接收来自 Windows 操作系统的所有消息。主窗口的消息处理函数会根据消息类型将消息路由到相应的 MFC 类。

  1. MFC 类根据消息映射将消息路由到相应的成员函数

每个 MFC 类都可以定义自己的消息映射,用于将 Windows 消息映射到成员函数。消息映射通常使用消息映射宏来定义。

  1. 成员函数处理消息并返回结果

当一个消息被路由到成员函数后,成员函数会根据消息类型和消息参数来处理消息。处理完成后,成员函数会返回一个结果。

消息处理过程示例

以下是一个典型的 MFC 消息处理过程示例:

  1. 用户点击一个按钮。
  2. Windows 操作系统将一个 WM_LBUTTONDOWN 消息发送给 MFC 应用程序。
  3. MFC 应用程序的主窗口接收消息并将其路由到按钮所在的窗口。
  4. 按钮所在的窗口的消息处理函数根据消息映射将消息路由到按钮的 OnClick 成员函数。
  5. OnClick 成员函数处理消息,例如更新按钮的文本或触发其他事件。
  6. OnClick 成员函数返回一个结果,指示消息是否已被处理。
消息处理过程的要点
  • MFC 消息处理过程是一个多层的消息路由机制。
  • 消息映射是 MFC 消息处理过程的关键。
  • 成员函数负责处理具体的 Windows 消息。

五.MFC 对象的创建

MFC 对象的创建通常包括以下几个步骤:

1.创建对象

使用 new 运算符创建一个 MFC 对象。例如,以下代码创建了一个 CDC 对象:

cpp 复制代码
CDC* pDC = new CDC;
2.初始化对象

调用 MFC 对象的初始化函数,如 CWnd::CreateCDocument::Open 等,来初始化对象的状态。例如,以下代码创建了一个窗口并初始化它的状态:

cpp 复制代码
CWnd* pWnd = new CWnd;
pWnd->Create(WS_OVERLAPPEDWINDOW, _T("My Window"), WS_VISIBLE | WS_CHILD, CRect(0, 0, 300, 200), CWnd::GetDesktopWindow(), IDD_MYDIALOG);
3.使用对象

调用 MFC 对象的成员函数来使用对象的功能。例如,以下代码使用 CDC 对象绘制一个矩形:

cpp 复制代码
pDC->Rectangle(10, 10, 200, 100);
4.销毁对象

当对象不再需要时,调用 delete 运算符销毁对象。例如,以下代码销毁 pDC 和 pWnd 对象:

cpp 复制代码
delete pDC;
delete pWnd;

六.应用程序的退出

MFC 应用程序的退出通常包括以下几个步骤:

1.处理未保存的数据

MFC 应用程序通常需要处理未保存的数据,如提示用户保存或自动保存。例如,以下代码提示用户保存文档:

cpp 复制代码
if (pDoc->IsModified())
{
    if (MessageBox(_T("是否保存文档?"), _T("提示"), MB_YESNO) == IDYES)
    {
        pDoc->Save();
    }
}

2.释放资源

MFC 应用程序需要释放占用的资源,如内存、文件句柄等。例如,以下代码释放内存:

cpp 复制代码
delete pDC;
delete pWnd;

3.注销 MFC DLL

MFC 应用程序需要注销 MFC DLL,释放 MFC 库占用的资源。例如,以下代码注销 MFC DLL:

cpp 复制代码
AfxOleUninitialize();

4.退出应用程序

MFC 应用程序调用 PostQuitMessage() 函数退出应用程序。例如,以下代码退出应用程序:

cpp 复制代码
PostQuitMessage(0);

总结

MFC 编程框架是 Windows 桌面应用程序开发的一套强大工具,它提供了一套丰富的类和函数,简化了 Windows 应用程序的开发过程。

MFC 抽象了 Win32 API 的细节,为程序员提供了一套统一的接口,使他们能够更容易地实现复杂的 Windows 应用程序。同时也 广泛应用于各种 Windows 桌面应用程序中,并提供了大量的类和函数供程序员使用。

相关推荐
Jtti42 分钟前
Windows系统服务器怎么设置远程连接?详细步骤
运维·服务器·windows
羊小猪~~1 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
小奥超人1 小时前
PPT文件设置了修改权限,如何取消权?
windows·经验分享·microsoft·ppt·办公技巧
脉牛杂德2 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz2 小时前
STL--哈希
c++·算法·哈希算法
CSUC2 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++
Vanranrr2 小时前
C++ QT
java·c++·qt
鸿儒5172 小时前
C++ lambda 匿名函数
开发语言·c++
van叶~3 小时前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
knighthood20013 小时前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros