深入浅出mfc之6大技术 运行时类型识别 DCLARE_DYNCREATE、DECLARE_DYNAMIC 、DECLARE_SERIAL、RUNTIME_CLASS、DECLARE_SERIAL 等
DECLARE_DYNAMIC 和 IMPLEMENT_DYNAMIC
IMPLEMENT_DYNAMIC是实现“运行时类型识别”宏,与之相对应的是DECLARE_DYNAMIC(声明“运行时类型识别”宏)。也就是说你在.CPP文件中如果看见有IMPLEMENT_DYNAMIC,则在.H文件中必定有DECLARE_DYNAMIC的声明。
DECLARE_DYNAMIC/DEClARE_DYNAMIC是为了确定运行时对象属于哪一个类而定义的宏。
DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE是为了“动态创建"类的实例而定义的宏。
#define DECLARE_DYNAMIC(class_name) /
public: /
static const CRuntimeClass class##class_name; /
virtual CRuntimeClass* GetRuntimeClass() const; /
#define IMPLEMENT_DYNAMIC(class_name,bass_class_name)\
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
static char _lpsz##class_name[]= #class_name;\
//定义一个C类型字符串静态变量,变量名由"_lpsz"和指定类的类名组成,变量值为该指定类型的名字
//比如是CMyView,那么定义的就是static char _lpszCMyView="CMyView";
CRuntimeClass class_name::class##class_name = {\
_lpsz##class_name,sizeof(class_name),wSchema,pfnNew,\
RUNTIME_CLASS(base_class_name),NULL};\
//给之前在DECLARE_DYNAMIC里定义的CRuntimeClass类型的静态成员变量赋值
//当然,除最后一个m_pNextClass没有赋值(赋值为NULL,它由下面的结构处理)
static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);\
//初始化一个名为"_init_##class_name"的AFX_CLASSINIT静态结构,主要作用是给指定的class_name的
//class##class_name静态变量的最后一个成员m_pNextClass赋值,具体见下面解释AFX_CLASSINIT中
CRuntimeClass* class_name::GetRuntimeClass
() const\
{ return &class_name::class##class_name;}\
//之前在DECLARE_DYNAMIC里定义的GetRuntimeClass的实现,很简单,就一个return语句。
#define RUNTIME_CLASS(class_name)\
(&class_name::class##class_name)
//这部分之所以单独define出一个宏,主要是为了方便从某个指定的class直接得到它的CRuntimeclass静态成员
RUNTIME_CLASS
RUNTIME_CLASS为class_name指定的类返回一个指向CRuntimeClass结构的指针。只有用DECLARE_DYNAMIC,DECLARE_DYNCREATE或DECLARE_SERIAL定义的CObject的派生类才能返回CRuntimeClass结构指针。利用这个宏通过C++类的名字获得一个运行时类结构。
MSDN曰:对于MFC中每个从CObject派生的类来说,都有一个相关的CRuntimeClass结构体,在程序运行时可以访问该结构体来获取对象及其基类的信息。
CRuntimeClass
CRuntimeClass是一个结构体,并且其本身并没有基类。
LPCSTR
m_lpszClassName
存放ASCII类名的以空字符结尾的字符串。
int
m_nObjectSize
以字节为单位给出对象的大小。若此对象具有指向被分配的内存的数据成员,则此值不包含该内存的大小。
UINT
m_wSchema
分类编号(对不可分类的类,该值为-1)。对于此分类编号的详细说明,参见IMPLEMENT_SERIAL宏。
CObject* ( PASCAL* m_pfnCreateObject )
是一个指向缺省的构造函数的函数指针,该构造函数创建一个你的类的对象(只有在类支持动态创建时才有
效;否则,返回NULL)。
CRuntimeClass* ( PASCAL* m_pfn_GetBaseClass )( )
如果你的应用程序是动态地链接到MFC的AFXDLL版本,则是一个指向函数的指针,该函数返回基类的
CRuntimeClass结构。
CRuntimeClass* m_pBaseClass
如果你的应用程序是静态地链接到MFC的,则是一个指向基类的CRuntimeClass结构的指针。
Feature Only in Professional and Enterprise Editions
只有在Visual C++的专业版和企业版中才支持对MFC的静态链接。
CObject* CreateObject( );
从CObject派生的类可以支持动态创建,这是在运行时创建一个指定类的对象的能力。例如,文档,视图和
框架类就应该支持动态创建。CreateObject成员函数可以用来实现这个功能,在运行时为这些类创建对象。
BOOL
IsDerivedFrom(
const
CRuntimeClass* pBaseClass)
const
;
如果IsDerivedFrom类成员的类是从基类派生而来,该基类的CRuntimeClass结构作为一个参数给出,则返
回 TRUE。IsDerivedFrom从该成员的类开始向上沿派生类链经过所有的类直到顶端,并且只有在没有与
基类匹配 的类时才返回FALSE。
GetRuntimeClass
获取当前视图类的正在运行的类 其返回值的类型为CRuntimeClass。
IsKindOf()
BOOL IsKindOf( const CRuntimeClass* pClass ) const;
类型识别,是在CObject 类中定义实现的。
检测pClass来查看:(1)对象是否属于指定的类,(2)对象是否属于指定类派生的类.,即同宗即可。
整个目的就是实现类别型录网,并且是链表的方式连接在一起。
从cobject 开始,每添加一个类,它自己就变成firstclasss。cobject是特殊的,静态static classobject = null;
而后面的继承的类都是使用DECLARE_DYNAMIC 和 IMPLEMENT_DYNAMIC的方式。
DECLARE_DYNCREATE( class_name ),
使用DECLARE_DYNCREATE宏可以使每个CObject的派生类的对象具有运行时动态创建的能力。框架利用这种能力来动态创建对象,例如,当它在串行化过程中从磁盘读取对象的时候。文档、视图和框架类必须支持动态创建,因为框架需要动态地创建它们。
在类的.H模块中加入DECLARE_DYNCREATE宏,然后在每个需要访问这个类的对象的.CPP模块中包含这个模块。
如果在类声明中包含了DECLARE_DYNCREATE,那么必须在类的实现中包含IMPLEMENT_DYNCREATE宏。
DECLARE_DYNCREATE 包含了DECLARE_DYNAMIC的功能,并且可以在运行过程中动态创建对象。如果需要动态创建类对象,需要使用这个宏定义。
#define DECLARE_DYNCREATE(class_name)\
DECLARE_DYNAMIC(class_name)\ //这个是声明了一个静态变量和函数,在前一节有说明
static CObject* _stdcall CreateObject(); //这个函数就是为了创建一个新的对象,返回对象指针。
IMPLEMENT_DYNCREATE(class_name,base_class_name)
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) "
CObject* PASCAL class_name::CreateObject() "
{ return new class_name; } "
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, "
class_name::CreateObject)
如在源文件中: IMPLEMENT_DYNCREATE(RenderView, CFormView)
CRuntimeClas的头文件声明里面,有一行非常奇怪的代码:
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
这行代码是声明了一个名叫 m_pfnCreateObject 的函数指针,这个函数指针的类型是 CObject* (PASCAL* )()。
m_pfnCreateObject就是“没有参数,返回CObject*”的一根函数指针。
这个指针指向的是你的类创建的默认构造函数(如果这个类支持动态创建,则是合法的,否则返回NULL)
m_pfnCreateObject是个函数指针,返回类型是CObject*, 没有函数参数().
最终,m_pfnCreateObject将会做的事情是 { return new class_name; },也就是{ return new YourClass; }
DECLARE_SERIAL / IMPLEMENT_SERIAL 宏
DECLARE_SERIAL也包含了DECLARE_DYNCREATE,它用于创建对象.
在头文件使用DECLARE_SERIA(类名)
在源文件使用 IMPLEMENT_SERIAL( CMyClass, CObject, VERSIONABLE_SCHEMA | 2 )
//第一个参数是你的类名,第bai二个参数是基类名,第三个参数是个版本号,你可以随便写。
#define DECLARE_SERIAL(class_name) \
DECLARE_DYNCREATE(class_name) \
friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject) \
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; } \
它大概有这么几个步骤:
1. 因为DECLARE_SERIAL重载了>>操作符,所以可以保证是调用CMessg类的>>函数.
2. >>函数实际上调用的是ar的ReadObject(CRuntimeClass*)函数
3. ReadObject首先从文件中读取类判断信息(可能是一个字符串,可能是一个类索引),得到Class对应的ClassName;
4. 程序的模块状态中有所有的RuntimeClass的列表,因此,查找对应的程序支持的RuntimeClass(对比ClassName),获得对应的RuntimeClass;
5. RuntimeClass中含有创建对象的方法CreateObject,调用它,创建对应的对象.这里,因为CreateObject实际就是 New 一个对象,类似 new CMessg; 所以,为了支持序列化,必须有没有参数的构造函数.
6. 创建对象之后,调用Seralize(ar),读入真正的对象的信息.
7. 将对象的指针返回.
8. pMessg就指向一个对应的对象了.
深入浅出mfc之6大技术 运行时类型识别 DCLARE_DYNCREATE、DECLARE_DYNAMIC 、DECLARE_SERIAL、RUNTIME_CLASS、DECLARE_SERIAL 等相关推荐
- java 运行时类型_Java基础之RTTI 运行时类型识别
运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于R ...
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别
RTTI(运行时类型识别) 参考文献:深入浅出MFC-侯捷 怎样去构造类别型录网? 一.定义数据结构: 其中pFirstClass指针属于痊愈变量,所以它应该以static修饰之. 而且我们最终希望达 ...
- MFC六大核心机制之二:运行时类型识别(RTTI)
上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...
- c++远征之多态篇——运行时类型识别(RTTI)
以下内容源于慕课网的学习整理,如有侵权,请告知删除. 1.RTTI(Run-Time Type Information),运行时类型识别. 涉及typeid.dynamic_cast这两个知识点. R ...
- RTTI机制(运行时类型识别)
RTTI机制(运行时类型识别) 在多态里面,基类里的虚函数和派生类里的虚函数形成了遮蔽,这就导致在主程序运行时,有些表达式的类型没有办法确定.必须等到程序运行结束后,根据具体的环境才能确定.看下面的代 ...
- C++ 学习笔记之(19) new、delete表达式、RTTI(运行时类型识别)、枚举、类成员指针、嵌套类、局部类、位域、volatile、extern C
C++ 学习笔记之(19) new.delete表达式.RTTI(运行时类型识别).枚举.类成员指针.嵌套类.局部类.位域.volatile.extern C C++ 学习笔记之(19) new.de ...
- Java RTTI运行时类型识别
RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. RTTI提供了以下两个非常有用的操作 ...
- 白话C++系列(27) -- RTTI:运行时类型识别
http://www.cnblogs.com/kkdd-2013/p/5601783.html RTTI-运行时类型识别 RTTI:Run-Time Type Identification. 那么RT ...
- C++11 的 运行时类型识别type_info
一.type_info与typeid 类type_info保存关于类型的特定于实现的信息,包括类型的名称,以及比较两个类型是否相等或排序顺序的方法. 这是typeid操作符返回的类.具有如下特点: ( ...
- C++知识点54——RTTI(运行时类型识别)
一.RTTI概述 RTTI的功能由两个运算符实现,一个是typeid,用来返回表达式的类型:另一个是dynamic_cast,作用是将基类的指针或引用安全地转为子类的指针或引用 二.typeid ty ...
最新文章
- WPF入门:数据绑定
- 金额大小写转换(1)
- WCF分布式开发必备知识(2):.Net Remoting
- Redis系列(十四)、Redis6新特性之RESP3与客户端缓存(Client side caching)
- 集算器并行处理大文本文件的示例
- mysql六:数据备份、pymysql模块
- 阿里Java开发手册——如何优化数据库?
- python post提交给php,从Python发送HTTP POST请求(尝试从PHP转换)
- [LeetCode]--35. Search Insert Position
- 高一计算机应用选择题,职业中学 高一《计算机应用基础》期末考试题
- Linux系统下CMake的安装和使用
- [2018.07.21 T2] 离家出走
- 计算器代码(C语言)
- xp系统怎么添加ntp服务器,1 Windows xp NTP服务器的配置
- Windows上的Oracle检查列表。 (文档ID 443813.1)
- 微信小程序 上滑加载和下拉刷新
- ply文件格式详细说明
- PHP经典高级工程师面试题
- Web超简单入门(附带项目的讲解)
- 金融借贷平台大数据风控解决方案
热门文章
- 《游戏设计师修炼之道:数据驱动的游戏设计》一1.4 来自政府和产业的挑战...
- ecshop lang用法
- 链表的实现(Java语言描述)
- python语法32[装饰器decorator](转)
- 提高Android应用辅助功能的方法Accessibility
- 【Sarah】第一周
- 2100 没有反弹shell_反弹shell | ncbash
- python剔除异常值的方法_二维d异常值的剔除方法
- 每天进步一点点 2016-10-28
- 热烈祝贺龙芯Loongarch OpenJDK8开源,已编译完成