随笔 - 3461, 文章 - 0, 评论 - 739, 阅读 - 1200万
  管理

MFC深入浅出-CObject类

Posted on   lzhdim  阅读(1066)  评论(0编辑  收藏  举报
CObject类

 

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

 

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

 

  1. 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特性的支持。

     

  2. CObject类的特性

     

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

  1. 对运行时类信息的支持

     

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

 

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

 

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

     

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

     

  1. 对动态创建的支持

     

前面提到了动态创建的概念,就是运行时创建指定类的实例。在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));

  1. 对序列化的支持

     

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

 

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

     

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

     

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

     

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

     

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

  1. 综合示例:

     

定义一个支持串行化的类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));

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
Copyright (C) 2000-2025 Lzhdim Software All Rights Reserved
点击右上角即可分享
微信分享提示