• (转)MFC的一些宏的整理 (DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE)


    很早看了MFC的一些宏的实现,什么RUNTIME_CLASS, DECLARE_DYNAMIC, DECLARE_DYNCREATE,IMPLEMENT_DYNCREATE, etc,看了就烦,现在整理下,免的忘了.

     代码实现

    (注:以下宏及其实现取自MFC)

    • DECLARE_DYNAMIC

    Define:
    #define DECLARE_DYNAMIC(class_name) "
    public: "
        static const AFX_DATA CRuntimeClass class##class_name; "
        virtual CRuntimeClass* GetRuntimeClass() const; "

    E.g.
    DECLARE_DYNAMIC(RenderView)
    (注:RenderView是继承于MFC中CFormView的一个类)

    Equals:

    public: 
        static const AFX_DATA CRuntimeClass classRenderView;
        virtual CRuntimeClass* GetRuntimeClass() const;

    即declare了一个static的CRuntimeClass变量和一个虚拟函数GetRuntimeClass()

    关于CRuntimeClass,其declaration:

    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;

    // 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
    };

    结构体,6个成员:
    m_lpszClassName 类名字
    m_nObjectSize 对象大小
    m_wSchema schema
    m_pfnCreateObject 函数指针 (对象创建方法)
    m_pBaseClass/m_pfnGetBaseClass 指向基类对象的指针/获取基类对象函数的指针 (Runtime的关键)
    m_pNextClass 指向下一个此类对象

    • DECLARE_DYNCREATE

    Define:
    // not serializable, but dynamically constructable
    #define DECLARE_DYNCREATE(class_name) "
        DECLARE_DYNAMIC(class_name) "
        static CObject* PASCAL CreateObject();


    E.g.
    DECLARE_DYNCREATE(RenderView)

    Equals:

    public: 
        static const AFX_DATA CRuntimeClass classRenderView;
        virtual CRuntimeClass* GetRuntimeClass() const;
        static CObject* PASCAL CreateObject();

    即declare了一个static的CRuntimeClass变量和一个虚拟函数GetRuntimeClass()和一个static的函数CreateObject()

    关于CObject,其declaration:

    #ifdef _AFXDLL
    class CObject
    #else
    class AFX_NOVTABLE CObject
    #endif
    {
    public:

    // Object model (types, destruction, allocation)
        virtual CRuntimeClass* GetRuntimeClass() const;
        virtual ~CObject();  // virtual destructors are necessary

        // Diagnostic allocations
        void* PASCAL operator new(size_t nSize);
        void* PASCAL operator new(size_t, void* p);
        void PASCAL operator delete(void* p);
    #if _MSC_VER >= 1200
        void PASCAL operator delete(void* p, void* pPlace);
    #endif

    #if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
        // for file name/line number tracking using DEBUG_NEW
        void* PASCAL operator new(size_t nSize, LPCSTR lpszFileName, int nLine);
    #if _MSC_VER >= 1200
        void PASCAL operator delete(void *p, LPCSTR lpszFileName, int nLine);
    #endif
    #endif

        // Disable the copy constructor and assignment by default so you will get
        //   compiler errors instead of unexpected behaviour if you pass objects
        //   by value or assign objects.
    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);

    #if defined(_DEBUG) || defined(_AFXDLL)
        // Diagnostic Support
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
    #endif

    // Implementation
    public:
        static const AFX_DATA CRuntimeClass classCObject;
    #ifdef _AFXDLL
        static CRuntimeClass* PASCAL _GetBaseClass();
    #endif
    };

    包含:GetRuntimeClass()方法,static变量 CRuntimeClass classCObject,static方法 _GetBaseClass() (为NULL,因为没有Base),IsKindOf()方法等.

    • RUNTIME_CLASS

    #define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

    E.g.
    RUNTIME_CLASS(RenderView)

    Equals:
    ((CRuntimeClass*)(&RenderView::classRenderView))
    即将classRenderView static变量转换成((CRuntimeClass*)指针

    • IMPLEMENT_RUNTIMECLASS

    Define:
    #define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) "
        AFX_COMDAT const AFX_DATADEF CRuntimeClass class_name::class##class_name = { "
            #class_name, sizeof(class class_name), wSchema, pfnNew, "
                RUNTIME_CLASS(base_class_name), NULL }; "
        CRuntimeClass* class_name::GetRuntimeClass() const "
            { return RUNTIME_CLASS(class_name); } "

    E.g.
    IMPLEMENT_RUNTIMECLASS(RenderView, CFormView, 0xFFFF, RenderView::CreateObject)

    Equals:
    AFX_COMDAT const AFX_DATADEF CRuntimeClass RenderView::classRenderView = { 
            #RenderView, sizeof(class RenderView), 0xFFFF, RenderView::CreateObject, 
                ((CRuntimeClass*)(&CFormView::classCFormView)), NULL }; 

        CRuntimeClass* RenderView::GetRuntimeClass() const 
            { return ((CRuntimeClass*)(&RenderView::classRenderView)); } 


    (##为连接文本, #RenderView为取RenderView字符串)

    即implement了static classRenderView变量和GetRuntimeClass()虚拟函数

    • IMPLEMENT_DYNCREATE

    Define:

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

    E.g.
    IMPLEMENT_DYNCREATE(RenderView, CFormView)

    Equals:

        CObject* PASCAL RenderView::CreateObject() 
            { return new RenderView; } 

        AFX_COMDAT const AFX_DATADEF CRuntimeClass RenderView::classRenderView = { 
            #RenderView, sizeof(class RenderView), 0xFFFF, RenderView::CreateObject, 
                ((CRuntimeClass*)(&CFormView::classCFormView)), NULL }; 

        CRuntimeClass* RenderView::GetRuntimeClass() const 
            { return ((CRuntimeClass*)(&RenderView::classRenderView)); } 

    即implement了static classRenderView变量和GetRuntimeClass()虚拟函数和CreateObject()函数.

    用途

    综合来看,这套宏的目的是在目标对象(比如RenderView)里面嵌套了一个CRuntimeClass对象,用来支持类似Runtime类型的查询转换等(用以支持MFC的RTTI?).

    支持这些,有什么用呢?一个用处是DYNAMIC_DOWNCAST,即MFC里实现的对象指针在类层次上的从上到下转换:
    E.g.
    ...
    pCFormView* pView = ...
    pRenderView* pRenderView = DYNAMIC_DOWNCAST(RenderView, pView)
    ...

    其实现如下:
    CObject* AFX_CDECL AfxDynamicDownCast(CRuntimeClass* pClass, CObject* pObject)
    {
        if (pObject != NULL && pObject->IsKindOf(pClass))
            return pObject;
        else
            return NULL;
    }

    BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
    {
        ASSERT(this != NULL);
        // it better be in valid memory, at least for CObject size
        ASSERT(AfxIsValidAddress(this, sizeof(CObject)));

        // simple SI case
        CRuntimeClass* pClassThis = GetRuntimeClass();
        return pClassThis->IsDerivedFrom(pClass);
    }

    BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
    {
        ASSERT(this != NULL);
        ASSERT(AfxIsValidAddress(this, sizeof(CRuntimeClass), FALSE));
        ASSERT(pBaseClass != NULL);
        ASSERT(AfxIsValidAddress(pBaseClass, sizeof(CRuntimeClass), FALSE));

        // simple SI case
        const CRuntimeClass* pClassThis = this;
        while (pClassThis != NULL)
        {
            if (pClassThis == pBaseClass)
                return TRUE;
    #ifdef _AFXDLL
            pClassThis = (*pClassThis->m_pfnGetBaseClass)();
    #else
            pClassThis = pClassThis->m_pBaseClass;
    #endif
        }
        return FALSE;       // walked to the top, no match
    }

    实现原理:RenderView继承自CFormView,后者又继承自CObject,它们本身又嵌套了static CRuntimeClass对象,那么查询一个指向CFormView对象的指针(pCFormView)是不是实际上就是一个指向RenderView对象的指针的功能是通过比较pCFormView指向的对象中的CRuntimeClass对象(或者其BaseRuntimeClass(或BaseRuntimeClass的BaseRuntimeClass...)对象)是不是就是(比较指针值)RenderView类所含的static CRuntimeClass对象(IsDerivedFrom方法)这么简单了?

    如果对象一样(即指针值相等)的话则可以转换成功,否则失败.

    (关键:嵌入的CRuntimeClass是静态的,可以通过类访问,又可以通过对象的非静态函数调用,这是实现的关键.因为继承于CObject层次上的每个类都有唯一的CRuntimeClass对象与之对应, 所以它可以成为类型的一个标识符,如果表示符一样了,那么肯定类型是一样的,而这个标识符既可以通过类访问又可以在运行时刻通过对象访问,所以取名CRuntimeClass.)

  • 相关阅读:
    HTTP解析
    Java设计模式8:迭代器模式
    Java设计模式7:适配器模式
    Sharepoint 开启发布功能的PowerShell
    How to Limit NodeRunner.exe High Memory, CPU Usage
    sharepoint 2013 网站集解锁
    SharePoint Set-SPUser 命令拒绝访问
    SharePoint 列表视图修改多行文本字段显示长度
    SharePoint 修改项目的new图标显示天数
    SharePoint 压缩打包文件代码分享
  • 原文地址:https://www.cnblogs.com/hongjiumu/p/3717244.html
Copyright © 2020-2023  润新知