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

很早看了MFC的一些宏的實現,什麼RUNTIME_CLASS, DECLARE_DYNAMIC, DECLARE_DYNCREATE,IMPLEMENT_DYNCREATE, etc,看了就煩,如今整理下,免的忘了.函數

 

 代碼實現this

(注:如下宏及其實現取自MFC)spa

  • 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()方法等.orm

  • 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()函數.get

 

用途it

綜合來看,這套宏的目的是在目標對象(好比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.)

相關文章
相關標籤/搜索