奇趣技术网 收藏本站
设为主页
商务合作
首页 新闻中心 行业动态 软件新闻 安全资讯 病毒预警 漏洞发布 操作系统 Dos Win9x Win2000 WinXP Win2003 WinVista Linux Unix
数据库 DB2 Access MSSQL MySQL Oracle Sybase 编程技术 ASP PHP JSP CGI/Perl XML .Net C/C++/C# VB VC Delphi Java 汇编
安全技术 安全教学 工具介绍 漏洞利用 病毒防范 入侵检测 防火墙 安全防范 汉化破解 攻击实例 加密解密 技术论坛
中华网络安全联盟 >> 程序开发 >> VC >> MFC六大关键技术剖析之动态创建
程序开发
Asp
PHP
JSP
CGI/Perl
XML
.Net
C/C++/C#
Visual Basic
Visual C++
Delphi
Java
汇编语言
  • VC中利用多线程技术实

  • 利用OpenGL实现三维绘

  • 基于Visual C++的Wins

  • 基于Visual C++6.0的D

  • Visual C++ MFC 中常用

  • 在MFC下如何定义全局变

  • 使用MFC在应用程序中嵌

  • VC++中进程与多进程管

  • MFC六大关键技术剖析之动态创建
    字体:

    中华网络安全联盟    作者:佚名    来源:网络转载    时间:2006-3-22

      动态创建就是运行时创建指定类的对象,在MFC中大量使用。如框架窗口对象、视对象,还有文档对象都需要由文档模板类对象来动态的创建。我觉得这是每个MFC的学习者很希望理解的问题。

      初次接触MFC的时候,很容易有这样的迷惘。MFC的几大类不用我们设计也就罢了,但最疑惑的是不用我们实例化对象。本来最直观的理解就是,我们需要框架的时候,亲手写上CFrameWnd myFrame;需要视的时候,亲自打上CView myView;……

      但MFC不给我们这个机会,致使我们错觉窗口没有实例化就弹出来了!就象画了张电视机的电路图就可以看电视一样令人难以置信。但大伙想了一下,可能会一拍脑门,认为简单不过:MFC自动帮我们完成CView myView之流的代码不就行了么!!!其实不然,写MFC程序的时候,我们几乎要对每个大类进行派生改写。换句话说,MFC并不知道我们打算怎样去改写这些类,当然也不打算全部为我们“静态”创建这些类了。即使静态了创建这些类也没有用,因为我们从来也不会直接利用这些类的实例干什么事情。我们只知道,想做什么事情就往各大类里塞,不管什么变量、方法照塞,塞完之后,我们似乎并未实例化对象,程序就可以运行!

      要做到把自己的类交给MFC,MFC就用同一样的方法,把不同的类一一准确创建,我们要做些什么事情呢?同样地,我们要建立链表,记录各类的关键信息,在动态创建的时候找出这些信息,就象上一节RTTI那样!我们可以设计一个类:

    struct CRuntimeClass{
     LPCSTR m_lpszClassName; //类名指针
     CObject* (PASCAL *m_pfnCreateObject)(); //创建对象的函数的指针
     CRuntimeClass* m_pBaseClass; //讲RTTI时介绍过
     CRuntimeClass* m_pNextClass; //指向链表的下一个元素(许多朋友说上一节讲RTTI时并没有用到这个指针,我原本以为这样更好理解一些,因为没有这个指针,这个链表是无法连起来,而m_pBaseClass仅仅是向基类走,在MFC的树型层次结构中m_pBaseClass是不能遍历的)

     CObject* CreateObject(); //创建对象
     static CRuntimeClass* PASCAL Load(); //遍历整个类型链表,返回符合动态创建的对象。
     static CRuntimeClass* pFirstClass; //类型链表的头指针
    };

      一下子往结构里面塞了那么多的东西,大家可以觉得有点头晕。至于CObject* (PASCAL *m_pfnCreateObject)();,这定义函数指针的方法,大家可能有点陌生。函数指针在C++书籍里一般被定为选学章节,但MFC还是经常用到此类的函数,比如我们所熟悉的回调函数。简单地说m_pfnCreateObject即是保存了一个函数的地址,它将会创建一个对象。即是说,以后,m_pfnCreateObject指向不同的函数,我们就会创建不同类型的对象。

      有函数指针,我们要实现一个与原定义参数及返回值都相同一个函数,在MFC中定义为:

    static CObject* PASCAL CreateObject(){return new XXX};//XXX为类名。类名不同,我们就创建不同的对象。

      由此,我们可以如下构造CRuntimeClass到链表:

    CRuntimeClass classXXX={
     类名,
     ……,
     XXX::CreateObject(), //m_pfnCreateObject指向的函数
     RUNTIME_CLASS(基类名) // RUNTIME_CLASS宏可以返回CRuntimeClass对象指针。
     NULL //m_pNextClass暂时为空,最后会我们再设法让它指向旧链表表头。
    };

      这样,我们用函数指针m_pfnCreateObject(指向CreateObject函数),就随时可new新对象了。并且大家留意到,我们在设计CRuntimeClass类对时候,只有类名(和基类名)的不同(我们用XXX代替的地方),其它的地方一样,这正是我们想要的,因为我们动态创建也象RTTI那样用到两个宏,只要传入类名和基类作宏参数,就可以满足条件。

      即是说,我们类说明中使用DECLARE_DYNCREATE(CLASSNMAE)宏和在类的实现文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏来为我们加入链表,至于这两个宏怎么为我们建立一个链表,我们自己可以玩玩文字代换的游戏,在此不一一累赘。但要说明的一点就是:动态创建宏xxx_DYNCREATE包含了RTTI宏,即是说, xxx_DYNCREATE是xxx_DYNAMIC的“增强版”。

      到此,我们有必要了解一下上节课没有明讲的m_pNextClass指针。因为MFC层次结构是树状的,并不是直线的。如果我们只有一个m_pBaseClass指针,它只会沿着基类上去,会漏掉其它分支。在动态创建时,必需要检查整个链表,看有多少个要动态创建的对象,即是说要从表头(pFirstClass)开始一直遍历到表尾(m_pNextClass=NULL),不能漏掉一个CRuntimeClass对象。

      所以每当有一个新的链表元素要加入链表的时候,我们要做的就是使新的链表元素成为表头,并且m_pNextClass指向原来链表的表头,即像下面那样(当然,这些不需要我们操心,是RTTI宏帮助我们完成的):

    pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;//新元素的m_pNextClass指针指向想加入的链表的表头。

    CRuntimeClass::pFirstClass=pNewClass;//链表的头指针指向刚插入的新元素。

      好了,有了上面的链表,我们就可以分析动态创建了。

        有一了张有类名,函数指针,动态创建函数的链表,我们就可以知道应该按什么步骤去动态创建了:

      1、获得一要动态创建的类的类名(假设为A)。

      2、将A跟链表里面每个元素的m_lpszClassName指向的类名作比较。

      3、若找到跟A相同的类名就返回A所属的CRuntimeClass元素的指针。

      4、判断m_pfnCreateObject是否有指向创建函数,有则创建对象,并返回该对象。

      代码演示如下(以下两个函数都是CRuntimeClass类函数):

      ///////////////以下为根据类名从表头向表尾查找所属的CRuntimeClass对象////////////

    CRuntimeClass* PASCAL CRuntimeClass::Load()
    {
     char szClassXXX[64];
     CRuntimeClass* pClass;
     cin>>szClassXXX; //假定这是我们希望动态创建的类名
     for(pClass=pFirstClass;pClass!=NULL;pClass=pClass->m_pNextClass)
     {
      if(strcmp(szClassXXX,pClass->m_lpszClassName)==0)
       return pClass;
     }
     return NULL
    }

    ///////////根据CRuntimeClass创建对象///////////

    CObject* CRuntimeClass::CreateObject()
    {
     if(m_pfnCreateObject==NULL) return NULL;
     CObject *pObject;
     pObject=(* m_pfnCreateObject)(); //函数指针调用
     return pObject;
    }

      有了上面两个函数,我们在程序执行的时候调用,就可以动态创建对象了。

      我们还可以更简单地实现动态创建,大家注意到,就是在我们的程序类里面有一个RUNTIME_CLASS(class_name)宏,这个宏在MFC里定义为:

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

      作用就是得到类的RunTime信息,即返回class_name所属CRuntimeClass的对象。在我们的应用程序员类(CMyWinApp)的InitInstance()函数下面的CSingleDocTemplate函数中,有:

    RUNTIME_CLASS(CMyDoc),

    RUNTIME_CLASS(CMainFrame), // main SDI frame window

    RUNTIME_CLASS(CMyView)

      构造文档模板的时候就用这个宏得到文档、框架和视的RunTime信息。有了RunTime信息,我们只要一条语句就可以动态创建了,如:

    classMyView->CreateObject(); //对象直接调用用CRuntimeClass本身的CreateObject()

      现在,细心的朋友已经能清楚动态创建需要的步骤:

      1、定义一个不带参数的构造函数(默认构造函数);因为我们是用CreateObject()动态创建,它只有一条语句就是return new XXX,不带任何参数。所以我们要有一个无参构造函数。

      2、类说明中使用DECLARE_DYNCREATE(CLASSNMAE)宏;和在类的实现文件中使用IMPLEMENT_DYNCREATE(CLASSNAME,BASECLASS)宏;这个宏完成构造CRuntimeClass对象,并加入到链表中。

      3、使用时先通过宏RUNTIME_CLASS得到类的RunTime信息,然后使用CRuntimeClass的成员函数CreateObject创建一个该类的实例。

      4、CObject* pObject = pRuntimeClass->CreateObject();//完成动态创建。

    字体:
     
    设为主页 收藏本站 联系我们 友情连接 商务合作 网友留言
    Copyright©2006-2008 中华网络安全联盟 All rights reserved.