ImageVerifierCode 换一换
你正在下载:

CObject.docx

[预览]
格式:DOCX , 页数:14 ,大小:30.92KB ,
资源ID:6166676      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6166676.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(CObject.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

CObject.docx

1、CObject3. CObject类 CObject是大多数MFC类的根类或基类。CObject类有很多有用的特性:对运行时类信息的支持,对动态创建的支持,对串行化的支持,对象诊断输出,等等。MFC从CObject派生出许多类,具备其中的一个或者多个特性。程序员也可以从CObject类派生出自己的类,利用CObject类的这些特性。本章将讨论MFC如何设计CObject类的这些特性。首先,考察CObject类的定义,分析其结构和方法(成员变量和成员函数)对CObject特性的支持。然后,讨论CObject特性及其实现机制。1. CObject的结构 以下是CObject类的定义:class C

2、Objectpublic:/与动态创建相关的函数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)

3、 & !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&

4、 objectSrc); / no implementation/ Attributespublic:/与运行时类信息、串行化相关的函数BOOL IsSerializable() const;BOOL IsKindOf(const CRuntimeClass* pClass) const;/ Overridablesvirtual void Serialize(CArchive& ar);/ 诊断函数virtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;/ Implementationpublic:

5、/与动态创建对象相关的函数static const AFX_DATA CRuntimeClass classCObject;#ifdef _AFXDLLstatic CRuntimeClass* PASCAL _GetBaseClass();#endif;由上可以看出,CObject定义了一个CRuntimeClass类型的静态成员变量:CRuntimeClass classCObject还定义了几组函数:构造函数析构函数类,诊断函数,与运行时类信息相关的函数,与串行化相关的函数。其中,一个静态函数:_GetBaseClass;五个虚拟函数:析构函数、GetRuntimeClass、Seria

6、lize、AssertValid、Dump。这些虚拟函数,在CObject的派生类中应该有更具体的实现。必要的话,派生类实现它们时可能要求先调用基类的实现,例如Serialize和Dump就要求这样。静态成员变量classCObject和相关函数实现了对CObjet特性的支持。2. CObject类的特性 下面,对三种特性分别描述,并说明程序员在派生类中支持这些特性的方法。1. 对运行时类信息的支持 该特性用于在运行时确定一个对象是否属于一特定类(是该类的实例),或者从一个特定类派生来的。CObject提供IsKindOf函数来实现这个功能。从CObject派生的类要具有这样的特性,需要: 定

7、义该类时,在类说明中使用DECLARE_DYNAMIC(CLASSNMAE)宏; 在类的实现文件中使用IMPLEMENT_DYNAMIC(CLASSNAME,BASECLASS)宏。 1. 对动态创建的支持 前面提到了动态创建的概念,就是运行时创建指定类的实例。在MFC中大量使用,如前所述框架窗口对象、视对象,还有文档对象都需要由文档模板类(CDocTemplate)对象来动态的创建。从CObject派生的类要具有动态创建的功能,需要: 定义该类时,在类说明中使用DECLARE_DYNCREATE(CLASSNMAE)宏; 定义一个不带参数的构造函数(默认构造函数); 在类的实现文件中使用IM

8、PLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏; 使用时先通过宏RUNTIME_CLASS得到类的RunTime信息,然后使用CRuntimeClass的成员函数CreateObject创建一个该类的实例。 例如:CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CNname)/CName必须有一个缺省构造函数CObject* pObject = pRuntimeClass-CreateObject();/用IsKindOf检测是否是CName类的实例Assert( pObject-IsKindOf(RUNTIME_CLA

9、SS(CName);1. 对序列化的支持 “序列化”就是把对象内容存入一个文件或从一个文件中读取对象内容的过程。从CObject派生的类要具有序列化的功能,需要: 定义该类时,在类说明中使用DECLARE_SERIAL(CLASSNMAE)宏; 定义一个不带参数的构造函数(默认构造函数); 在类的实现文件中使用IMPLEMENT_SERIAL(CLASSNAME,BASECLASS)宏; 覆盖Serialize成员函数。(如果直接调用Serialize函数进行序列化读写,可以省略前面三步。) 对运行时类信息的支持、动态创建的支持、串行化的支持层(不包括直接调用Serailize实现序列化),这

10、三种功能的层次依次升高。如果对后面的功能支持,必定对前面的功能支持。支持动态创建的话,必定支持运行时类信息;支持序列化,必定支持前面的两个功能,因为它们的声明和实现都是后者包含前者。1. 综合示例: 定义一个支持串行化的类CPerson:class CPerson : public CObjectpublic:DECLARE_SERIAL( CPerson )/ 缺省构造函数CPerson();CString m_name;WORD m_number;void Serialize( CArchive& archive );/ rest of class declaration;实现该类的成员函

11、数Serialize,覆盖CObject的该函数:void CPerson:Serialize( CArchive& archive )/ 先调用基类函数的实现CObject:Serialize( archive );/ now do the stuff for our specific classif( archive.IsStoring() )archive m_name m_name m_number;使用运行时类信息:CPerson a; ASSERT( a.IsKindOf( RUNTIME_CLASS( CPerson ) ) );ASSERT( a.IsKindOf( RUNTI

12、ME_CLASS( CObject ) ) );动态创建:CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CPerson)/Cperson有一个缺省构造函数CObject* pObject = pRuntimeClass-CreateObject();Assert( pObject-IsKindOf(RUNTIME_CLASS(CPerson); 1. 实现CObject特性的机制 由上,清楚了CObject的结构,也清楚了从CObject派生新类时程序员使用CObject特性的方法。现在来考察这些方法如何利用CObjet的结构,CObject结构如何

13、支持这些方法。首先,要揭示DECLARE_DYNAMIC等宏的内容,然后,分析这些宏的作用。1. DECLARE_DYNAMIC等宏的定义 MFC提供了DECLARE_DYNAMIC、DECLARE_DYNCREATE、DECLARE_SERIAL声明宏的两种定义,分别用于静态链接到MFC DLL和动态链接到MFC DLL。对应的实现宏IMPLEMNET_XXXX也有两种定义,但是,这里实现宏就不列举了。MFC对这些宏的定义如下:#ifdef _AFXDLL /动态链接到MFC DLL#define DECLARE_DYNAMIC(class_name) protected: static C

14、RuntimeClass* PASCAL _GetBaseClass(); public: static const AFX_DATA CRuntimeClass class#class_name; virtual CRuntimeClass* GetRuntimeClass() const; #define _DECLARE_DYNAMIC(class_name) protected: static CRuntimeClass* PASCAL _GetBaseClass(); public: static AFX_DATA CRuntimeClass class#class_name; vi

15、rtual CRuntimeClass* GetRuntimeClass() const; #else#define DECLARE_DYNAMIC(class_name) public: static const AFX_DATA CRuntimeClass class#class_name; virtual CRuntimeClass* GetRuntimeClass() const; #define _DECLARE_DYNAMIC(class_name) public: static AFX_DATA CRuntimeClass class#class_name; virtual CR

16、untimeClass* GetRuntimeClass() const; #endif/ not serializable, but dynamically constructable#define DECLARE_DYNCREATE(class_name) DECLARE_DYNAMIC(class_name) static CObject* PASCAL CreateObject();#define DECLARE_SERIAL(class_name) _DECLARE_DYNCREATE(class_name) friend CArchive& AFXAPI operator(CArc

17、hive& ar, class_name* &pOb);由于这些声明宏都是在CObect派生类的定义中被使用的,所以从这些宏的上述定义中可以看出,DECLARE_DYNAMIC宏给所在类添加了一个CRuntimeClass类型的静态数据成员class#class_name(类名加前缀class,例如,若类名是CPerson,则该变量名称是classCPerson),且指定为const;两个(使用MFC DLL时,否则,一个)成员函数:虚拟函数GetRuntimeClass和静态函数_GetBaseClass(使用MFC DLL时)。DECLARE_DYNCREATE宏包含了DECLARE_DY

18、NAMIC,在此基础上,还定义了一个静态成员函数CreateObject。DECLARE_SERIAL宏则包含了_DECLARE_DYNCREATE,并重载了操作符“”(友员函数)。它和前两个宏有所不同的是CRuntimeClass数据成员class#class_name没有被指定为const。对应地,MFC使用三个宏初始化DECLARE宏所定义的静态变量并实现DECLARE宏所声明的函数:IMPLEMNET_DYNAMIC,IMPLEMNET_DYNCREATE,IMPLEMENT_SERIAL。首先,这三个宏初始化CRuntimeClass类型的静态成员变量class#class_name

19、。IMPLEMENT_SERIAL不同于其他两个宏,没有指定该变量为const。初始化内容在下节讨论CRuntimeClass时给出。其次,它实现了DECLARE宏声明的成员函数: _GetBaseClass() 返回基类的运行时类信息,即基类的CRuntimeClass类型的静态成员变量。这是静态成员函数。 GetRuntimeClass() 返回类自己的运行类信息,即其CRuntimeClass类型的静态成员变量。这是虚拟成员函数。对于动态创建宏,还有一个静态成员函数CreateObject,它使用C+操作符和类的缺省构造函数创建本类的一个动态对象。 操作符的重载 对于序列化的实现宏IMP

20、LEMENT_SERIAL,还重载了操作符(CArchive& ar, class_name* &pOb) pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name);return ar;回顾CObject的定义,它也有一个CRuntimeClass类型的静态成员变量classCObject,因为它本身也支持三个特性。以CObject及其派生类的静态成员变量classCObject为基础,IsKindOf和动态创建等函数才可以起到作用。这个变量为什么能有这样的用处,这就要分析CRuntimeClass类型变量的结构和内容了。下面,在讨

21、论了CRuntimeClass的结构之后,考察该类型的静态变量被不同的宏初始化之后的内容。1. CruntimeClass类的结构与功能 从上面的讨论可以看出,在对CObject特性的支持上,CRuntimeClass类起到了关键作用。下面,考查它的结构和功能。1. CRuntimeClass的结构 CruntimeClass的结构如下:Struct CRuntimeClassLPCSTR m_lpszClassName;/类的名字int m_nObjectSize;/类的大小UINT m_wSchema;CObject* (PASCAL* m_pfnCreateObject)();/poin

22、ter to function, equal to newclass.CreateObject() /after IMPLEMENTCRuntimeClass* (PASCAL* m_pfnGetBaseClass)();CRumtieClass* m_pBaseClass;/operator:CObject *CreateObject();BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;.CRuntimeClass成员变量中有两个是函数指针,还有几个用来保存所在CruntimeClass对象所在类的名字、类的大小(字节数)等

23、。这些成员变量被三个实现宏初始化,例如:m_pfnCreateObject,将被初始化指向所在类的静态成员函数CreateObject。CreateObject函数在初始化时由实现宏定义,见上文的说明。m_pfnGetBaseClass,如果定义了_AFXDLL,则该变量将被初始化指向所在类的成员函数_GetBaseClass。_GetBaseClass在声明宏中声明,在初始化时由实现宏定义,见上文的说明。下面,分析三个宏对CObject及其派生类的CRuntimeClass类型的成员变量class#class_name初始化的情况,然后讨论CRuntimeClass成员函数的实现。2. 成员

24、变量class#class_name的内容 IMPLEMENT_DYNCREATE等宏将初始化类的CRuntimeClass类型静态成员变量的各个域,表3-1列出了在动态类信息、动态创建、序列化这三个不同层次下对该静态成员变量的初始化情况:表3-1 静态成员变量class#class_name的初始化CRuntimeClass成员变量 动态类信息 动态创建 序列化 m_lpszClassName 类名字符串 类名字符串 类名字符串 m_nObjectSize 类的大小(字节数) 类的大小(字节数) 类的大小(字节数) m_wShema 0xFFFF 0xFFFF 1、2等,非0 m_pfnCr

25、eateObject NULL 类的成员函数CreateObject 类的成员函数CreateObject m_pBaseClass 基类的CRuntimeClass变量 基类的CRuntimeClass变量 基类的CRuntimeClass变量 m_pfnGetBaseClass 类的成员函数_GetBaseClass 类的成员函数_GetBaseClass 类的成员函数_GetBaseClass m_pNextClass NULL NULL NULL m_wSchema类型是UINT,定义了序列化中保存对象到文档的程序的版本。如果不要求支持序列化特性,该域为0XFFFF,否则,不能为0。C

26、object类本身的静态成员变量classCObject被初始化为: CObject, sizeof(CObject), 0xffff, NULL, &CObject:_GetBaseClass, NULL ;对初始化内容解释如下:类名字符串是“CObject”,类的大小是sizeof(CObject),不要求支持序列化,不支持动态创建。3. 成员函数CreateObject 回顾3.2节,动态创建对象是通过语句pRuntimeClass-CreateObject完成的,即调用了CRuntimeClass自己的成员函数,CreateObject函数又调用m_pfnCreateObject指向的

27、函数来完成动态创建任务,如下所示:CObject* CRuntimeClass:CreateObject()if (m_pfnCreateObject = NULL) /判断函数指针是否空TRACE(_T(Error: Trying to create object which is not )_T(DECLARE_DYNCREATE nor DECLARE_SERIAL: %hs.n),m_lpszClassName);return NULL;/函数指针非空,继续处理CObject* pObject = NULL;TRYpObject = (*m_pfnCreateObject)(); /动

28、态创建对象END_TRYreturn pObject;4. 成员函数IsDerivedFrom 该函数用来帮助运行时判定一个类是否派生于另一个类,被CObject的成员函数IsKindOf函数所调用。其实现描述如下:如果定义了_AFXDLL则,成员函数IsDerivedFrom调用成员函数m_pfnGetBaseClass指向的函数来向上逐层得到基类的CRuntimeClass类型的静态成员变量,直到某个基类的CRuntimeClass类型的静态成员变量和参数指定的CRuntimeClass变量一致或者追寻到最上层为止。如果没有定义_AFXDLL,则使用成员变量m_pBaseClass基类的C

29、RuntimeClass类型的静态成员变量。程序如下所示:BOOL CRuntimeClass:IsDerivedFrom(const CRuntimeClass* pBaseClass) constASSERT(this != NULL);ASSERT(AfxIsValidAddress(this, sizeof(CRuntimeClass), FALSE);ASSERT(pBaseClass != NULL);ASSERT(AfxIsValidAddress(pBaseClass, sizeof(CRuntimeClass), FALSE);/ simple SI caseconst CRuntimeClass* pClassThis = this;while (pClassThis != NULL)/从本类开始向上逐个基类搜索if (pClassThis = pBaseClass)/若是参数指定的类信息return TRUE;/类信息不符合,继续向基类搜索#ifdef _AFXDLLpClassThis = (*pClassThis-m_pfnGetBaseClass)();#elsepC

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1