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

多多的爹

 
 
 

日志

 
 

深入解析MFC -- 动态创建(CRuntimeClass)  

2008-01-22 16:58:36|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

先说句客气话,很久没有更新此系列了,这段时间太闲,所以人也太懒
再说句屎话,这几天的股市,真是tmd的狗屎啊
最后再说句屁话,MFC的动态创建,就是一个屁!
CRuntimeClass作为一个很奇怪的存在,在MFC中的地位还很高,但是很多书上都没有说这个东西到底有什么用,还是看看他的代码吧:
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
#ifdef _AFXDLL
    CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
#else
    CRuntimeClass* m_pBaseClass;
#endif

// Operations
    CObject* CreateObject();
    BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;

    // dynamic name lookup and creation
    static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
    static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
    static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
    static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);

// Implementation
    void Store(CArchive& ar) const;
    static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);

    // CRuntimeClass objects linked together in simple list
    CRuntimeClass* m_pNextClass;       // linked list of registered classes
    const AFX_CLASSINIT* m_pClassInit;
};
由以上声明,可以看出这个结构体有几个作用:
1.记录并提供类信息(注意,是类信息,不是类对象信息)。包括类的名字,大小,schema(这个东西据说是在存文件时用来标志版本信息的)
2.动态创建对象
3.对象存储

虽然1不是本文的重点,还是提一下。C++有一个RTTI的功能,可以找到类的名字。但MFC开发小组开发MFC时,C++语言项目组还没有提供这个功能,所以自己搞了一个RTCI的功能,其核心就是CRuntimeClass。一个与CRuntimeClass绑定的类(注意,是类,不是类对象),可以通过CRuntimeClass,知道自己的类名。
3在序列化中会提到,这里不多说。

具体说2,说说为什么是个屁。
按照我的理解,所谓动态创建,应该满足两个条件:
条件1,创建过程不依赖类声明,可以根据某个标记,或名字,或ID,来创建对象
条件2,使用过程不依赖类声明,引用和保存类对象不需要了解类声明
而这两个条件,MFC都没有做到。CRuntimeClass以类工厂的形式,提供了两种创建对象的方式。但是这两种方式都没有脱离被创建类声明。
先说第一种,通过成员函数CreateObject(非静态)创建对象:
CObject* CRuntimeClass::CreateObject()
{
    return (*m_pfnCreateObject)();
}
此方式需要CRuntimeClass对象。不巧的是,CRuntimeClass对象的声明正好位于其被创建的类中。
例如,创建一个多文档程序,打开文件MainFrm.h,在CMainFrame的声明中,第一句就是DECLARE_DYNAMIC(CMainFrame)。展开这个宏:
protected:
    static CRuntimeClass* PASCAL _GetBaseClass();
public:
    static const CRuntimeClass classCMainFrame;
    static CRuntimeClass* PASCAL GetThisClass();
    virtual CRuntimeClass* GetRuntimeClass() const;
静态成员变量classCMainFrame就是类工厂对象。
因此通过这种方式创建对象,首选需要将此头文件include,违背条件1。

第二种方式,通过静态成员函数CreateObject创建对象:
CObject* PASCAL CRuntimeClass::CreateObject(LPCSTR lpszClassName)
{
    CRuntimeClass* pClass = FromName(lpszClassName);
    return pClass == NULL ? NULL : pClass->CreateObject();
}
这种方式只需要类名称,就能创建对象。听起来很美,但调用后你会发现,CreateObject返回的永远是NULL,为什么,因为FromName返回的总是NULL。看看FromName的实现:
CRuntimeClass* PASCAL CRuntimeClass::FromName(LPCSTR lpszClassName)
{
    CRuntimeClass* pClass=NULL;
    AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
    for (pClass = pModuleState->m_classList; pClass != NULL; pClass = pClass->m_pNextClass)
    {
        if (lstrcmpA(lpszClassName, pClass->m_lpszClassName) == 0)
        {
            return pClass;
        }
    }
    return NULL; // not found
}
FromName从AFX_MODULE_STATE的m_classList中找的CRuntimeClass对象。如何将CRuntimeClass对象放到这个list中?在CRuntimeClass的声明上面,我找到了这个函数:
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
{
    AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
    pModuleState->m_classList.AddHead(pNewClass);
}
如此简单。我马上在CYourApp的InitInstance中添加了如下代码:
AfxClassInit(RUNTIME_CLASS(CYourDoc));
AfxClassInit(RUNTIME_CLASS(CChildFrame));
AfxClassInit(RUNTIME_CLASS(CYourView));
理论上以后无论在哪里,都可以动态这三个类了。编译运行,嘭的一声,出错了:
void CSimpleList::AddHead(void* p)
{
    *GetNextPtr(p) = m_pHead;
}
错误就出在上面这行代码。原因很简单,这句话妄图给CRuntimeClass的m_pClassInit赋值,很不幸,CRuntimeClass对象被声明成了const。
因此,这条路根本就走不通。条件1仍然没有被满足。

其实无论用哪种方式,创建出来的对象都必须用类指针来记住,在MFC中没有接口的概念,因此注定离不开对类声明的引用,此为违背条件2。

  评论这张
 
阅读(40)| 评论(5)
推荐 转载

历史上的今天

评论

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

页脚

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