天天看點

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

轉載于:https://www.cnblogs.com/soroman/archive/2009/02/28/1400413.html

繼續閱讀