很早看了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.)

(转)MFC的一些宏的整理 (DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE)的更多相关文章

  1. VC++/MFC 最常用宏和指令

    1.#include指令  包含指定的文件,最基本的最熟悉的指令,编程中不得不用,包含库文件用双尖括号,包含自定义头文件用双引号. 2.#define指令   预定义,通常用它来定义常量(包括无参量与 ...

  2. C++编译时函数名修饰约定规则(很具体),MFC提供的宏,extern "C"的作用

    调用约定: __cdecl __fastcall与 __stdcall,三者都是调用约定(Calling convention),它决定以下内容:1)函数参数的压栈顺序,2)由调用者还是被调用者把参数 ...

  3. 程序员需要有多懒 ?- cocos2d-x 数学函数、常用宏粗整理

    原帖地址:http://www.cnblogs.com/buaashine/archive/2012/11/12/2765691.html 1.注意这是cocos2d-x中的函数,但大体上和cocos ...

  4. 【转】MFC消息映射详解(整理转载)

    消息:主要指由用户操作而向应用程序发出的信息,也包括操作系统内部产生的消息.例如,单击鼠标左按钮,windows将产WM_LBUTTONDOWN消息,而释放鼠标左按钮将产生WM_LBUTTONUP消息 ...

  5. MFC宏

    1,DECLARE_MESSAGE_MAP:在头文件中声明源文件中所含有的消息映射 2,BEGIN_MESSAGE_MAP:标记源文件消息映射的开始 3,END_MESSAGE_MA:标记源文件消息映 ...

  6. MFC宏常识

    1.宏就是用宏定义指令#define定义一个标识符,用它来表示一个字符串或一段源代码. MFC宏作为MFC类库的一个组成部分在MFC应用程序中经常出现. MFC宏在路径 ".../Micro ...

  7. excel宏整理

    工作以后发现excel很强大,用好excel已经成功工作中很重要的一部分内容,最近写了一些宏, 整理如下: 根据excel生成sql脚本的sc_template Sub GenSCTemplateFi ...

  8. iOS - 常用宏定义和PCH文件知识点整理

    (一)PCH文件操作步骤演示: 第一步:图文所示: 第二步:图文所示: (二)常用宏定义整理: (1)常用Log日志宏(输出日志详细可定位某个类.某个函数.某一行) //=============== ...

  9. 《深入浅出MFC》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <深入浅出MFC>内含光盘一片,书中所有原始码与可执行文件尽在其中. 作者简介 侯俊杰,先生不知何许人也,闲静少言,不慕荣利.好读书,求甚解:每有 ...

随机推荐

  1. 网络最大流问题之Ford-Fulkerson算法原理详解

    前言 最大流问题是网络优化中典型的问题,用形象的语言来描述就是在满足容量约束的前提下将尽可能多的流从源节点(始点)到汇节点(终点).解决此问题的经典方法很多,本文介绍广为人熟知的Ford-Fulker ...

  2. java系列: 对不起,JavaFX——Java 8目前还不能救你(zz)

    JavaFX 是SUN公司在2007年JavaOne大会上首次对外公布的以Java为基础构建的富客户端平台,更让开发者印象比较深刻的则是其背后的JavaFX开发团队,仅仅在两年的时间就从1.0版本完善 ...

  3. Tomcat简易安装指南

    由于要学习activiti的使用,而activiti依赖于tomcat,所以下载了一个tomcat 7 的binary包,然后按照running.TXT中的描述来手动安装,下文主要是记录了在阅读run ...

  4. linux内核分析 课程总结

    Linux内核分析 链接汇总 Linux内核分析第一周学习总结--计算机是如何工作的 Linux内核分析第二周学习总结--操作系统是如何工作的 Linux内核分析第三周学习总结--构造一个简单的Lin ...

  5. 20135328信息安全系统设计基础第一周学习总结(Linux应用)

    学习计时:共xxx小时 读书: 代码: 作业: 博客: 一.学习目标 1. 能够独立安装Linux操作系统   2. 能够熟练使用Linux系统的基本命令   3. 熟练使用Linux中用户管理命令/ ...

  6. 【原创】基于Memcached 实现用户登录的Demo(附源码)

    一个简单的Memcached在Net中运用的一个demo.主要技术 Dapper+MVC+Memcached+sqlserver, 开发工具为vs2015+Sql 效果图如下: 登录后 解决方案 主要 ...

  7. AngularJS - 路由入门

    我们有很多方法让一个视图随着用户的操作进行变化. 但是,只是单单一个视图就要满足所有的需求会让代码变得非常复杂. 也许我们可以使用ng-include来引用各种模板,但这只限于部分场景. 于是我们可以 ...

  8. Intelli IDEA 14.04开发版+注册码

    Idea,一款比较出色的IDE开发工具,懂她的人,自然懂得. 本版本-14.04+注册码 注册界面  注册码:               Name:happy                KEY: ...

  9. ztree点击文字勾选checkbox,radio实现方法

    ztree的复选框checkbok,单选框radio是用背景图片来模拟的,所以点击文字即使用label括起checkbox,radio文字一起,点击文字也是无法勾选checkbox. 要想点击ztre ...

  10. TinyMCE(富文本编辑器)

    [转]TinyMCE(富文本编辑器)在Asp.Net中的使用方法 官网演示以及示例代码:https://www.tinymce.com/docs/demo/image-tools/ 转自:http:/ ...