MFC深入浅出-CObject类

简介: CObject类   CObject 是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。
CObject类

 

CObject 是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。

 

本章将讨论 MFC如何设计CObject类的这些特性。首先,考察CObject类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。然后,讨论CObject特性及其实现机制。

 

CObject的结构

 

以下是 CObject类的定义:

 

class CObject

{

public:

// 与动态创建相关的函数

 

virtual CRuntimeClass* GetRuntimeClass() const;

析构函数

virtual ~CObject(); // virtual destructors are necessary

// 与构造函数相关的内存分配函数,可以用于DEBUG下输出诊断信息

 

void* PASCAL operator new(size_t nSize);

void* PASCAL operator new(size_t, void* p);

void PASCAL operator delete(void* p);

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)

void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);

#endif

// 缺省情况下,复制构造函数和赋值构造函数是不可用的

 

// 如果程序员通过传值或者赋值来传递对象,将得到一个编译错误

 

protected:

// 缺省构造函数

 

CObject();

private:

// 复制构造函数,私有

 

CObject(const CObject& objectSrc); // no implementation

// 赋值构造函数,私有

 

void operator=(const CObject& objectSrc); // no implementation

// Attributes

public:

// 与运行时类信息、串行化相关的函数

 

BOOL IsSerializable() const;

BOOL IsKindOf(const CRuntimeClass* pClass) const;

// Overridables

virtual void Serialize(CArchive& ar);

// 诊断函数

 

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

// Implementation

public:

// 与动态创建对象相关的函数

 

static const AFX_DATA CRuntimeClass classCObject;

#ifdef _AFXDLL

static CRuntimeClass* PASCAL _GetBaseClass();

#endif

};

由上可以看出, CObject定义了一个CRuntimeClass类型的静态成员变量:

 

CRuntimeClass classCObject

还定义了几组函数:

构造函数析构函数类,

诊断函数,

与运行时类信息相关的函数,

与串行化相关的函数。

其中,一个静态函数: _GetBaseClass;五个虚拟函数:析构函数、GetRuntimeClass、Serialize、AssertValid、Dump。这些虚拟函数,在CObject的派生类中应该有更具体的实现。必要的话,派生类实现它们时可能要求先调用基类的实现,例如Serialize和Dump就要求这样。

 

静态成员变量 classCObject和相关函数实现了对CObjet特性的支持。

 

CObject类的特性

 

下面,对三种特性分别描述,并说明程序员在派生类中支持这些特性的方法。

对运行时类信息的支持

 

该特性用于在运行时确定一个对象是否属于一特定类(是该类的实例),或者从一个特定类派生来的。 CObject提供IsKindOf函数来实现这个功能。

 

从 CObject派生的类要具有这样的特性,需要:

 

定义该类时,在类说明中使用 DECLARE_DYNAMIC(CLASSNMAE)宏;

 

在类的实现文件中使用 IMPLEMENT_DYNAMIC(CLASSNAME,BASECLASS)宏。

 

对动态创建的支持

 

前面提到了动态创建的概念,就是运行时创建指定类的实例。在MFC中大量使用,如前所述框架窗口对象、视对象,还有文档对象都需要由文档模板类(CDocTemplate)对象来动态的创建。

从CObject派生的类要具有动态创建的功能,需要:

定义该类时,在类说明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;

 

定义一个不带参数的构造函数(默认构造函数);

 

在类的实现文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;

 

使用时先通过宏RUNTIME_CLASS得到类的RunTime信息,然后使用CRuntimeClass的成员函数CreateObject创建一个该类的实例。

 

例如:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CNname)

//CName 必须有一个缺省构造函数

 

CObject* pObject = pRuntimeClass->CreateObject();

// 用IsKindOf检测是否是CName类的实例

 

Assert( pObject->IsKindOf(RUNTIME_CLASS(CName));

对序列化的支持

 

“序列化”就是把对象内容存入一个文件或从一个文件中读取对象内容的过程。从 CObject派生的类要具有序列化的功能,需要:

 

定义该类时,在类说明中使用DECLARE_SERIAL(CLASSNMAE)宏;

 

定义一个不带参数的构造函数(默认构造函数);

 

在类的实现文件中使用IMPLEMENT_SERIAL(CLASSNAME,BASECLASS)宏;

 

覆盖Serialize成员函数。(如果直接调用Serialize函数进行序列化读写,可以省略前面三步。)

 

对运行时类信息的支持、动态创建的支持、串行化的支持层(不包括直接调用Serailize实现序列化),这三种功能的层次依次升高。如果对后面的功能支持,必定对前面的功能支持。支持动态创建的话,必定支持运行时类信息;支持序列化,必定支持前面的两个功能,因为它们的声明和实现都是后者包含前者。

综合示例:

 

定义一个支持串行化的类CPerson:

class CPerson : public CObject

{

public:

DECLARE_SERIAL( CPerson )

// 缺省构造函数

CPerson(){}{};

CString m_name;

WORD m_number;

void Serialize( CArchive& archive );

 

// rest of class declaration

} ;

 

实现该类的成员函数 Serialize,覆盖CObject的该函数:

 

void CPerson::Serialize( CArchive& archive )

{

// 先调用基类函数的实现

 

CObject::Serialize( archive );

// now do the stuff for our specific class

if( archive.IsStoring() )

archive << m_name << m_number;

else

archive >> m_name >> m_number;

}

使用运行时类信息:

CPerson a;

ASSERT( a.IsKindOf( RUNTIME_CLASS( CPerson ) ) );

ASSERT( a.IsKindOf( RUNTIME_CLASS( CObject ) ) );

动态创建:

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson)

//Cperson 有一个缺省构造函数

 

CObject* pObject = pRuntimeClass->CreateObject();

Assert( pObject->IsKindOf(RUNTIME_CLASS(CPerson));

目录
相关文章
|
存储
汇编语言中“$”的作用
汇编语言中“$”的作用
2410 0
汇编语言中“$”的作用
|
JavaScript 前端开发 IDE
QCAD v3.23.0.2源码编译,使用VS2017+Qt5.12.5环境
QCAD v3.23.0.2源码编译,使用VS2017+Qt5.12.5环境
1328 0
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
抖音封号一般封多久?
根据2023年9月更新的《抖音创作者权益保护指引》,平台将封号时长划分为四级响应机制:
|
8月前
|
人工智能 固态存储 iOS开发
5分钟搞定Photoshop 2025安装:官方下载+许可证激活避坑指南
Adobe Photoshop 2025 是 Adobe 公司推出的最新图像处理软件,广泛应用于平面设计、摄影后期和 UI 设计等领域。其核心功能包括智能 AI 工具(一键抠图、生成填充等)、高效工作流(优化图层管理与色彩调整)、跨平台兼容(支持 Windows 11 和 macOS 15)以及云协作功能(与 Adobe Creative Cloud 集成)。本文详细介绍软件的安装流程、系统要求、正版激活方法及常见问题解决方案,并提供扩展学习资源,帮助用户更好地掌握这款强大工具。
31366 3
|
移动开发 Java API
大疆无人机对接
本文介绍了大疆无人机对接第三方云平台的方案,包括设备对接和CloudAPI对接两种方式,重点讨论了CloudAPI对接。CloudAPI对接方案通过DJI Pilot 2或大疆机场将无人机与第三方云平台连接,实现低门槛接入,无需重复开发APP。方案优势在于让开发者更专注于业务开发,而非无人机功能适配。文章详细阐述了对接流程,包括环境准备、申请APPKey、对接流程、直播功能及获取无人机实时数据等内容,并提供了丰富的接口说明和技术支持资源。
7303 4
大疆无人机对接
|
11月前
|
存储 缓存 资源调度
阿里云服务器经济型、通用算力型、计算型、通用型、内存型实例区别与选择指南
在我们通过阿里云的活动选购云服务器的时候会发现,相同配置的云服务器往往有多个不同的实例可选,而且价格差别也比较大,这会是因为不同实例规格的由于采用的处理器不同,底层架构也有所不同(例如X86 计算架构与Arm 计算架构),因此不同实例的云服务器其性能与适用场景是有所不同。本文将详细解析阿里云的经济型、通用算力型、计算型、通用型和内存型实例的性能特点及适用场景,帮助用户根据自己的业务需求做出明智的选择。
|
存储 前端开发 JavaScript
前端的全栈之路Meteor篇(四):RPC方法注册及调用-更轻量的服务接口提供方式
RPC机制通过前后端的`callAsync`方法实现了高效的数据交互。后端通过`Meteor.methods()`注册方法,支持异步操作;前端使用`callAsync`调用后端方法,代码更简洁、易读。本文详细介绍了Methods注册机制、异步支持及最佳实践。
260 3
|
SQL 开发框架 数据库
在Python中使用sqlalchemy来操作数据库的几个小总结
在Python中使用sqlalchemy来操作数据库的几个小总结
|
容器
C++17新特性之try_emplace与insert_or_assign
由于std::map中,元素的key是唯一的,我们经常遇到这样的场景,向map中插入元素时,先检测map指定的key是否存在,不存在时才做插入操作,如果存在,直接取出来使用,或者key不存在时,做插入操作,存在时做更新操作。
309 0
|
安全 网络协议
子域名在线扫描 -- dnsdumpster
子域名在线扫描 -- dnsdumpster
1008 0