注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

重读深入浅出MFC(1)---RTTI及动态创建  

2011-07-10 11:16:59|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

重读深入浅出MFC(1)---RTTI及动态创建
从网上淘了一本<深入浅出MFC>,经典的东西可以不断翻来看去,原来兄弟和朋友们学习VC,我基本不再推荐他们细致的学习MFC了,但随着在新WIN7中重新启用了MFC,所以一些东西又有学习的必要了.有时间开始重读经典,并写下一些笔记.
前面简单的略过,我们直接进入动态创建中的一个小问题,就是在下面的类中,PASCAL* m_pfnCreateObject这个函数指针是在哪里赋值的?
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
CRuntimeClass* m_pBaseClass;
CObject* CreateObject();
static CRuntimeClass* PASCAL Load();
// CRuntimeClass objects linked together in simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
这个得从头一点点儿的剥开,我们在DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE宏中看到有这样一段代码 :
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \class_name::CreateObject)
对上面的代码说明一下,网上很多初学者问那个\是什么意思,那表明这段代码一行无法写完,下面的接着,连接符的意思,可以这样认为.
这个宏展开:
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name,wSchema,pfnNew) \
static char _lpsz##class_name[] = #class_name; \
CRuntimeClass class_name::class##class_name = { \
_lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return &class_name::class##class_name; } \

看上去很吓人吧,哈哈,我们套进去一个具体的类你就明白了:
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)它展开:
static char _lpszCFrameWnd[] = "CFrameWnd";
CRuntimeClass CFrameWnd::classCFrameWnd = {
_lpszCFrameWnd, sizeof(CFrameWnd), 0xFFFF, CFrameWnd::CreateObject,
RUNTIME_CLASS(CWnd), NULL };
static AFX_CLASSINIT _init_CFrameWnd(&CFrameWnd::classCFrameWnd);
CRuntimeClass* CFrameWnd::GetRuntimeClass() const
{ return &CFrameWnd::classCFrameWnd; }

从里面再看这段:
CRuntimeClass CFrameWnd::classCFrameWnd = {
_lpszCFrameWnd, sizeof(CFrameWnd), 0xFFFF, CFrameWnd::CreateObject,
RUNTIME_CLASS(CWnd), NULL };
学过C和C++滴同学们明白了吧,结构体在直接初始化,只不过这里用了宏定义,宏定义就是麻烦啊,一个很简单的东西,整得如此的复杂,考验人的耐力和精神啊.

所以应该明白了吧,上文提出的问题是在这里做出得解答m_pfnCreateObject = CFrameWnd::CreateObject(),注意,CFrameWnd::CreateObject()是个静态的函数,直接创建一个类的对象返回就没事儿了.要提醒的是,在CRuntimeClass类里有CreateObject()函数,在宏开后塞进(这是候大人的原话)各个模拟类(CView,CFrameWnd等)里面也有,前者是用来在主程序里控制生成CRuntimeClass中CObject的指针,然后再通过这个指针操作塞进的CreateObject()来创建真正的类对象.
这里书上说是如果这个指针是空的话说明是抽象基类.这个很简单,因为抽象基类没有这个函数呗,哈哈.
然后说下CRuntimeClass中的UINT m_wSchema,这个小细节一般人不会注意,要想弄明白这个东东,得看一下IMPLEMENT_SERIAL( class_name, base_class_name, wSchema )这个宏,相当滴麻烦,微软这样说滴:A UINT "version number" that will be encoded in the archive to enable a deserializing program to identify and handle data created by earlier program versions. The class schema number must not be –1. 就是说这是一个版本号,用来在文档中识别是否可反串行化(就是读串行化保存的数据,拗口)及其以前的文档,这个值不能为-1,其实的意思我们明白了,如果为-1(即0xFFFF)说明这个类不能串行化,如果能串行化,就要标记版本,好让人知道这个东西是第一次存入啊,还是第几次,这个是不断的修改的.或者说:此个参数地意思就为此部分文档地版本号,例如你在某个文档里面用呢两个类作对象存储,开始,两个的wSchema都定义设置为1,后来想改其中一个类地存储结构,那么就把wSchema改成2就可以呢。便于对文件异常错误地处理
最后我们再讲RTTI,讲一下IsKindOf和RUNTIME_CLASS,讲到这里我们就得拉出来DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC这两个宏,全是宏,大家不要晕,我们不细讲它们,如果有想详细知道的看书去,通过他,我们可以将类通过CRuntimeClass的对象链接起来,我们在用IsKindOf时,只要遍历这个链表就可以了.从当前类一直遍历他的所有的父类,如果相等产,就返回TRUE.有同学会问,哪来的链表啊?就是没有细讲的DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC这两个宏.

今天暂时说到这里,有时间接着.
记于北京上地.

  评论这张
 
阅读(743)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017