zoukankan      html  css  js  c++  java
  • MFC深入浅出CObject类

    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));

  • 相关阅读:
    LeetCode 32. 最长有效括号(Longest Valid Parentheses)
    LeetCode 141. 环形链表(Linked List Cycle)
    LeetCode 160. 相交链表(Intersection of Two Linked Lists)
    LeetCode 112. 路径总和(Path Sum)
    LeetCode 124. 二叉树中的最大路径和(Binary Tree Maximum Path Sum)
    LightGBM新特性总结
    sql service 事务与锁
    C#泛型实例详解
    C# 中的委托和事件(详解)
    C# DateTime日期格式化
  • 原文地址:https://www.cnblogs.com/lzhdim/p/1343793.html
Copyright © 2011-2022 走看看