MFC六大关键技术之永久保存(串行化)

MFC下保存文件大全 串口收文件时以及MFC下文件接收和保存,VC环境下文件接收和保存总结 立即下载
MFC六大关键技术之永久保存(串行化)
先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!

如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。

对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此,可让大家感受到面向对象的幸福。

MFC
的连续存储(serialize)机制俗称串行化。“在你的程序中尽管有着各种各样的数据,serialize机制会象流水一样按顺序存储到单一的文件中,而又能按顺序地取出,变成各种不同的对象数据。”不知我在说上面这一句话的时候,大家有什么反应,可能很多朋友直觉是一件很简单的事情,只是说了一个“爽”字就没有下文了。

要实现象流水一样存储其实是一个很大的难题。试想,在我们的程序里有各式各样的对象数据。如画图程序中,里面设计了点类,矩形类,圆形类等等,它们的绘图方式及对数据的处理各不相同,用它们实现了成百上千的对象之后,如何存储起来?不想由可,一想头都大了:我们要在程序中设计函数store(),在我们单击“文件/保存”时能把各对象往里存储。那么这个store()函数要神通广大,它能清楚地知道我们设计的是什么样的类,产生什么样的对象。大家可能并不觉得这是一件很困难的事情,程序有能力知道我们的类的样子,对象也不过是一块初始化了存储区域罢了。就把一大堆对象“转换”成磁盘文件就行了。

即使上面的存储能成立,但当我们单击“文件/打开”时,程序当然不能预测用户想打开哪个文件,并且当打开文件的时候,要根据你那一大堆垃圾数据new出数百个对象,还原为你原来存储时的样子,你又该怎么做呢?

试想,要是我们有一个能容纳各种不同对象的容器,这样,用户用我们的应用程序打开一个磁盘文件时,就可以把文件的内容读进我们程序的容器中。把磁盘文件读进内存,然后识别它“是什么对象”是一件很难的事情。首先,保存过程不像电影的胶片,把景物直接映射进去,然后,看一下胶片就知道那是什么内容。可能有朋友说它象录像磁带,拿着录像带我们看不出里面变化的磁场信号,但经过录像机就能把它还原出来。

其实不是这样的,比如保存一个矩形,程序并不是把矩形本身按点阵存储到磁盘中,因为我们绘制矩形的整个过程只不过是调用一个GDI函数罢了。它保存只是坐标值、线宽和某些标记等。程序面对“00 FF”这样的东西,当然不知道它是一个圆或是一个字符!

拿刚才录像带的例子,我们之所以能最后放映出来,前提我们知道这对象是“录像带”,即确定了它是什么类对象。如果我们事先只知道它“里面保存有东西,但不知道它是什么类型的东西”,这就导致我们无法把它读出来。拿录像带到录音机去放,对录音机来说,那完全是垃圾数据。即是说,要了解永久保存,要对动态创建有深刻的认识。

现在大家可以知道困难的根源了吧。我们在写程序的时候,会不断创造新的类,构造新的对象。这些对象,当然是旧的类对象(如MyDocument)从未见过的。那么,我们如何才能使文档对象可以保存自己新对象呢,又能动态创建自己新的类对象呢?

许多朋友在这个时候想起了CObject这个类,也想到了虚函数的概念。于是以为自己“大致了解”串行化的概念。他们设想:“我们设计的MyClass(我们想用于串行化的对象)全部从CObject类派生,CObject类对象当然是MyDocument能认识的。”这样就实现了一个目的:本来MyDocument不能识别我们创建的MyClass对象,但它能识别CObject类对象。由于MyClass从CObject类派生,我产的新类对象“是一个CObject”,所以MyDocument能把我们的新对象当作CObiect对象读出。或者根据书本上所说的:打开或保存文件的时候,MyDocument会调用Serialize(),MyDocument的Serialize()函会呼叫我们创建类的Serialize函数[即是在MyDocument Serialize()中调用:m_pObject->Serialize(),注意:在此m_pObject是CObject类指针,它可以指向我们设计的类对象]。最终结果是MyDocument的读出和保存变成了我们创建的类对象的读出和保存,这种认识是不明朗的。

有意思还有,在网上我遇到几位自以为懂了Serialize的朋友,居然不约而同的犯了一个很低级得让人不可思议的错误。他们说:Serialize太简单了!Serialize()是一个虚函数,虚函数的作用就是“优先派生类的操作”。所以MyDocument不实现Serialize()函数,留给我们自己的MyClass对象去调用Serialize()……真是哭笑不得,我们创建的类MyClass并不是由MyDocument类派生,Serialize()函数为虚在MyDocument和MyClass之间没有任何意义。MyClass产生的MyObject对象仅仅是MyDocument的一个成员变量罢了。

话说回来,由于MyClass从CObject派生,所以CObject类型指针能指向MyClass对象,并且能够让MyClass对象执行某些函数(特指重载的CObject虚函数),但前提必须在MyClass对象实例化了,即在内存中占领了一块存储区域之后。不过,我们的问题恰恰就是在应用程序随便打开一个文件,面对的是它不认识的MyClass类,当然实例化不了对象。

幸好我们在上一节课中懂得了动态创建。即想要从CObject派生的MyClass成为可以动态创建的对象只要用到DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏就可以了(注意:最终可以Serialize的对象仅仅用到了DECLARE_SERIAL/IMPLEMENT_SERIAL宏,这是因为DECLARE_SERIAL/IMPLEMENT_SERIAL包含了DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏)。

从解决上面的问题中,我们可以分步理解了:

1
、 Serialize的目的:让MyDocument对象在执行打开/保存操作时,能读出(构造)和保存它不认的MyClass类对象。

2
、 MyDocument对象在执行打开/保存操作时会调用它本身的Serialize()函数。但不要指望它会自动保存和读出我们的MyClass类对象。这个问题很容易解决,就直接在MyDocument:: Serialize(){

// 
在此函数调用MyClass类的Serialize()就行了!即

MyObject. Serialize
();

}

3
、我们希望MyClass对象为可以动态创建的对象,所以要求在MyClass类中加上DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC宏。

但目前的Serialize机制还很抽象。我们仅仅知道了表面上的东西,实际又是如何的呢?下面作一个简单深刻的详解。

先看一下我们文档类的Serialize()

void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
目前这个子数什么也没做(没有数据的读出和写入),CMyDoc类正等待着我们去改写这个函数。现在假设CMyDoc有一个MFC可识别的成员变量m_MyVar,那么函数就可改写成如下形式:

void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring()) //
读写判断
{
ar<<m_MyVar; //
写
}
else
{
ar>>m_MyVar; //
读
}
}

许多网友问:自己写的类(即MFC未包含的类)为什么不行?我们在CMyDoc里包含自写类的头文件MyClass.h,这样CMyDoc就认识MyDoc类对象了。这是一般常识性的错误,MyDoc类认识MyClass类对象与否并没有用,关键是CArchive类,即对象ar不认识MyClass(当然你梦想重写CArchive类当别论)。“>>”、“<<”都是CArchive重载的操作符。上面ar>>m_MyVar说白即是在执行一个以ar和m_MyVar 为参数的函数,类似于function(ar,m_MyVar)罢了。我们当然不能传递一个它不认识的参数类型,也因此不会执行function(ar,m_MyObject)了。

[
注:这里我们可以用指针。让MyClass从Cobject派生,一切又起了质的变化,假设我们定义了:MyClass *pMyClass = new MyClass;因为MyClass从CObject派生,根据虚函数原理,pMyClass也是一个CObject*,即pMyClass指针是CArchive类可认识的。所以执行上述function(ar, pMyClass),即ar << pMyClass是没有太多的问题(在保证了MyClass对象可以动态创建的前提下)。]



回过头来,如果想让MyClass类对象能Serialize,就得让MyClass从CObject派生,Serialize()函数在CObject里为虚,MyClass从CObject派生之后就可以根据自己的要求去改写它,象上面改写CMyDoc::Serialize()方法一样。这样MyClass就得到了属于MyClass自己特有的Serialize()函数。

现在,程序就可以这样写:
…
#include “MyClass.h”
……
void CMyDoc::Serialize(CArchive& ar)
{
//
在此调用MyClass重写过的Serialize()
m_MyObject. Serialize(ar); // m_MyObject
为MyClass实例
}

至此,串行化工作就算完成了,一即简单直观:从CObject派生自己的类,重写Serialize()。在此过程中,我刻意安排:在没有用到DECLARE_SERIAL/IMPLEMENT_SERIAL宏,也没有用到CArray等模板类的前提下就完成了串行化的工作。我看过某些书,总是一开始就讲DECLARE_SERIAL/IMPLEMENT_SERIAL宏或马上用CArray模板,让读者觉得串行化就是这两个东西,导致许多朋友因此找不着北。

大家看到了,没有DECLARE_SERIAL/IMPLEMENT_SERIAL宏和CArray等数据结构模板也依然可以完成串行化工作。


现在可以腾出时间讲一下大家觉得十分抽象的CArchive。我们先看以下程序(注:以下程序包含动态创建等,请包含DECLARE_SERIAL/IMPLEMENT_SERIAL宏)

void MyClass::Serialize(CArchive& ar)
{
if (ar.IsStoring()) //
读写判断
{
ar<< m_pMyVar; //
问题:ar 如何把m_pMyVar所指的对象变量保存到磁盘?
}
else
{
pMyClass = new MyClass; //
准备存储空间
ar>> m_pMyVar;
}
}

要回答上面的问题,即“ar<<XXX”的问题。和我们得看一下模拟CArchive的代码。

“ar<<XXX”
是执行CArchive对运算符“<<”的重载动作。ar和XXX都是该重载函数中的一参数而已。函数大致如下:

CArchive& operator<<( CArchive& ar, const CObject* pOb)
{
…………
//
以下为CRuntimeClass链表中找到、识别pOb资料。
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
//
保存pClassRef即类信息(略)
((CObject*)pOb)->Serialize();//
保存MyClass数据
…………
}

从上面可以看出,因为Serialize()为虚函数,即“ar<<XXX”的结果是执行了XXX所指向对象本身的Serialize()。对于“ar>>XXX”,虽然不是“ar<<XXX”逆过程,大家可能根据动态创建和虚函数的原理料想到它。

至此,永久保存算是写完了。在此过程中,我一直努力用最少的代码,详尽的解释来说明问题。以前我为本课题写过一个版本,并在几个论坛上发表过,但不知怎么在网上遗失(可能被删除)。所以这篇文章是我重写的版本。记得第一个版本中,我是对DECLARE_SERIAL/IMPLEMENT_SERIAL和可串行化的数组及链表对象说了许多。这个版本中我对DECLARE_SERIAL/IMPLEMENT_SERIAL其中奥秘几乎一句不提,目的是让大家能找到中心,有更简洁的永久保存的概念,我觉得这种感觉很好!
 
MFC文档的串行化与保存 MFC 文档串行化 保存 立即下载

相关推荐

mfc 串行化的简单使用

简单介绍串行化的使用(即序列化),在保存文件格式的时候较实用,方便,适合mfc初学者

串行化(Serialization)

串行化(Serialization)转载自:VC知识库 作者:阿荣串行化是微软提供的用于对对象进行文件I/O的一种机制,该机制在框架(Frame)/文档(Document)/视图(View) 模式中得到了很好的应用。很多人对什么是串行化、怎么使对象具有串行化能力和如何使用串行化功能等问题都不甚明了。本文试图对串行化做一个简单的解释。由于本人对串行化功能使用的也不多,不足之处敬请谅解。 MFC 框架

larntin 1957

mfc中如何保存到.txt文档中?.rar

mfc中如何保存到.txt文档中?.rar

MFC数据的保存和打开

MFC中数据的保存和打开有三种处理方式: 第一种:CFileDialog + CFile数据结构体 使用传统的File类,通过这个类的Open、write、read等函数对要保存的数据进行保存。但是使用这种方式保存,就需要将要保存的数据定制成一个结构体,以结构体的对象对数据进行保存。使用这种方式存储数据,有可能会造成数据存储控件的浪费,并且操作不方便。 第二种:CFileDialog + CFile+ CArchive: 使用CArchive这个类,CArchive类对CFile类再封装之后不再使用结构体作

qq_43812868的博客 7381

MFC的文件串行化操作

在MFC中使用文档类提供的串行化类进行文件的写入以及读取,保存图形的一些特征(比如起点和终点、画笔和画刷的类型)并进行图形的重绘。

链路监控pinpoint3.0.3安装部署(2)

本文详细介绍了Pinpoint 3.0.3分布式链路监控系统的安装部署过程。主要内容包括:1)数据库安装(HBase、MySQL、Redis、Pinot)的详细配置步骤;2)中间件Zookeeper和Kafka的安装;3)Pinpoint三大组件的部署:Collector、Web和Batch的配置文件修改和启动脚本。文章特别强调了使用-starter-exec.jar包的重要性,并提供了各组件所需的详细参数配置,包括数据库连接、Zookeeper地址、Kafka配置等关键信息。

zouzou_888的博客 1376

串行化

MFC的默认文件菜单,提供了“新建”、“打开”、“保存”“另存为”等功能。序列化(串行化)是微软提供的用于对对象进行文件I/O的一种机制,该机制在框架(Frame)/文档(Document)/视图(View) 模式中得到了很好的应用。“打开”、“保存”、“另存为”都涉及到对象的串行化。 一、       串行化条件 一个类若需要支持串行化,则需要: Ø  这个类从CObject派生。串行化要

WUYUAN2011WOAINI的专栏 2817

未隔离电源设备使用usb转串口调试导致串口模块爆炸烧坏事故记录

这个事就发生在前两天,我们公司的wifi模块被客户用到了咖啡机上,客户寄了一台整机给我们协助调试,还送了几包咖啡豆,本想着还能打个咖啡喝一喝的,但就在咖啡机刚寄过来第一天,就出事了。而这个事故的发生,竟然仅仅是因为同事接了个串口模块到电脑调试打印导致的。谁也想不到,这个3.3V的供电的wifi模块居然还有这么大的威力。直接将usb转TTL串口模块的转换芯片给爆开了,咖啡机也给弄坏了,据同事描述当时情况就只见到一片火光和一声巨响,状况比较惨烈,所幸的是笔记本电脑没有烧坏,但是直接给崩蓝屏了。 ...

fangye945a的博客 6195

MFC串行化原理

MFC串行化原理 作者:flyfish 2014-2-8 简介   本文章源码分析MFC的版本是10.0(VC2010) 串行化Serialization简单说就是在程序中定义的对象转换成连续的字节数据,无论这种连续的字节数据是在内存还是存储在硬盘上。程序重启之后,读取硬盘的数据,可以根据硬盘上的数据生成一个新的对象。   数据的读写 CArchive类 串行化的前提 从获取的文

二分掌柜的 4878

法律AI工具横评:Kimi Work与WorkBuddy,谁更适合法律人?

在人工智能技术日益普及的今天,自然语言处理(NLP)和大语言模型(LLM)正深刻改变着专业领域的工作范式。其核心原理在于通过海量数据训练,使模型能够理解、生成和推理人类语言。这一技术价值在于将从业者从繁琐、重复的信息处理工作中解放出来,极大提升工作效率与知识获取的便捷性。在法律、金融、咨询等对文本处理要求极高的行业,AI助手已展现出在文档分析、信息检索和内容生成方面的巨大潜力。具体到法律应用场景,AI工具能够辅助完成合同审查、法律检索和文书起草等核心任务,成为专业人士的得力助手。本文聚焦于近期备受关注的两款

weixin_30279671的博客 562

AI工程化之生成式UI & A2UI(二)

本文介绍了生成式UI框架A2UI的架构设计与核心实现。项目采用AI协作开发模式,通过ATDD(AI驱动的测试驱动开发)确保代码质量。前端SDK基于zustand实现框架无关的状态管理,包含协议解析器、存储管理、渲染器等核心模块。重点展示了基础store构建、A2UI协议解析器的实现过程,包括mock数据准备、测试用例生成和可视化调试。项目采用monorepo管理,利用vite实现高效开发构建。整个系统设计遵循模块化原则,通过清晰的接口定义实现各组件解耦,为后续功能扩展打下基础。

qq_34306228的博客 407

MFC 文档串行化

参考:孙鑫C++视频第十三讲 一、建立一个串行化类的五个步骤(参考MSDN:CObject::Serilize)        1、建立一个可串行化类,可串行化类都是从CObject继承而来        2、重载Serialize成员函数        3、在类声明中使用DECLARE_SERIAL宏        4、定义一个没有参数的构造函数    

u010901792的专栏 642

AAAI2024最佳解读|FontDiffuser One-Shot Font Generation via Denoising Diffusion with Multi-Scal

本文提出了一种名为FontDiffuser的基于扩散的单次字体生成方法,旨在通过去噪扩散模型生成模仿参考图像风格的字体,同时保留源图像的内容。尽管现有的字体生成方法在性能上取得了一定的进展,但在处理复杂字符和大风格变化时仍面临挑战。FontDiffuser通过引入多尺度内容聚合(MCA)模块,有效结合不同尺度的全局和局部内容线索,从而增强复杂字符的笔画保留能力。此外,文章还提出了一种风格对比细化(SCR)模块,用于风格表示学习,利用风格提取器从图像中分离风格,并通过精心设计的风格对比损失来监督扩散模型。

haimianxiaobao11的博客 1193

MFC六大关键技术之(四)——永久保存(串行化)

 用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此,可让大家感受到面向对象的幸福。MFC的连续存储(ser

Gary·hou专栏 2458

ubuntu20.04屏幕亮度无法调节(亮度条调节无效)的简单靠谱解决方案及踩坑历程

0 前言   网上关于ubuntu系统亮度无法调节的问题的解决方法有很多,但是绝大部分并没有什么用(这也是我自己的亲身体会),或者并不靠谱。在遍尝各路方法过后,我终于解决了这一棘手的问题(毕竟最大亮度真的非常刺眼,无法长时间直视),在此记录一下踩坑历程以及最后的解决方案。 1 Naive方法   由于使用需要,最近在电脑原有的win10基础上安装了ubuntu双系统。我安装的是当前新版的ubuntu20.04.2.0,靠谱的安装教程可以参考这里。   之前师兄说双ssd安装双系统会有系统启动引导的问题出现,

zeeq的博客 4万+

静态时序分析(STA)—— 标准单元库

目录 1、时序库 概览 2、时序模型 1、基本概念 2、影响因素 3、线性延时模型 4、非线性延时模型 5、单元时序弧 1、组合逻辑单元 2、时序逻辑单元 6、线负载模型 参考说明 上一篇,学习了 STA相关的基本概念,本篇继续学习 STA相关的 标准单元库。 1、时序库 概览 库文件概览: 2、时序模型 1、基本概念 2、影响因素 对于组合逻辑的时序弧而言,其延时的大小取决于: 1、输出负载,即,输出端的电容负载的大小。容性负载越大,...

记录所学,分享知识,结识挚友 2855

MFC六大关键技术(第四部分)——永久保存(串行化)

MFC---串行化       先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了!       如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。       对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此,

迷途小书童 1523

ANSYS软件二次开发(2):二次开发环境搭建与配置

ADK是ANSYS提供的一个开发工具包,它包含了用于二次开发的API、示例代码和开发指南。ADK支持Python和Tcl,但Python因其易用性和强大的社区支持,成为首选。在ANSYS软件中,自定义菜单与工具栏是实现二次开发的重要途径之一,它允许用户根据自己的需求和工作流程,创建个性化的操作界面。通过自定义菜单与工具栏,可以将常用的功能、自定义的脚本或宏命令整合到一起,提高工作效率。原因:材料参数输入错误,或者模型的物理假设与实际情况不符。解决方案仔细校验材料参数,确保与实验数据一致。

kkchenjj的博客 2206

MFC六大关键技术(4)——永久保存(串行化)

MFC六大关键技术(第四部分)——永久保存(串行化) 先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了! 如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。 对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此

yazhouren的专栏 1270

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

剖析MFC六大关键技术 四 永久保存(串行化)

如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。  对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此,可让大家感受到面向对象的幸福。  MFC的连续存储(serialize)机制俗称串行化。“在你的程序中尽管有着各种各样的数据,

sunnyorange的专栏 622

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

剖析MFC六大关键技术 四 永久保存(串行化)

先用一句话来说明永久保存的重要:弄懂它以后,你就越来越像个程序员了! 如果我们的程序不需要永久保存,那几乎可以肯定是一个小玩儿。那怕我们的记事本、画图等小程序,也需要保存才有真正的意义。 对于MFC的很多地方我不甚满意,总觉得它喜欢拿一组低能而神秘的宏来故弄玄虚,但对于它的连续存储(serialize)机制,却是我十分钟爱的地方。在此,可让大家感受到面向对象的幸福。 MFC的连续存储(serial

761

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

上一篇: MFC六大关键技术之动态创建
下一篇: MFC六大关键技术之消息映射与命令传递
Simkon
博客等级 码龄16年 1粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值