《深入浅出MFC》– MFC六大关键技术之仿真、RTTI、动态创建

1.六大关键技术:

①:MFC程序的初始化过程

②:RTTI(Runtime Type Information) 运行时类型识别

③:Dynamic Creation 动态创建

④:Persistence 永久保存

⑤:Message Mapping 消息映射

⑥:Message Routing 消息传递

 

2.MFC数个之最重要的类的层次关系:

image

CMyWinApp theApp;

void main(){

        CWinApp* pApp = AfxGetApp();

        pApp->InitApplication();

        pApp->InitInstance();

        pAPP->Run();

}

构造、析构次序:

CObject 构造->CCmdTarget构造->CWinThread构造->CWinApp构造->CMyWinApp构造

CMyWinApp析构->CWinApp析构->CWinThread析构->CCmdTarget析构造->CObject 析构

main执行顺序:

CWinApp::InitApplication->CMyWinApp::InitInstance->CMyFrameWnd::CMyFrameWnd->CFrameWnd::Create->CWnd::CreateEx->CFrameWnd::PreCreateWindow->CWinApp::Run->CWinThread::Run

 

3.RTTI(运行时识别)

要达到RTTI的能力,我们(类库的设计者)一定要在类建构起来的时候,记录必要的信息,以建立型录。型录中的类信息,最好以链表方式连接起来,将来方便一一比较。

我们这份“类型型录”的链表元素将以CRuntimeClass描述之。

struct CRuntimeClass

{

      LPCSTR  m_lpszClassName;

      int  m_nObjectSize;

      UINT   m_wSchema;

      CObect*  (PASCAL*  m_pfnCreateObject)();

      CRuntimeClass*   m_pBaseClass;            //基类

      static  CRuntimeClass *  pFirstClass;        

      CRuntimeClass*  m_pNextClass;         //下一个注册类

};

image

我们希望,每一个类都能拥有这样一个CRuntimeClass成员变量,并且最好有一定的命名规则(例如在类名称之前冠以“class”作为它的名称),然后,经由某种手段将整个类库建构好之后,“类别型录”能呈现类似这样的风貌:

image

为了神不知鬼不觉把CRuntimeClass对象塞到类之中,并声明一个可用抓到该对象地址的函数,我们定义DECLARE_DYNAMIC宏如下:

#define   DECLARE_DYNAMIC(class_name) \

public: \

            static  CRuntimeClass  class##class_name;  \

            virtual   CRuntimeClass*   GetRuntimeClass() const;

##用来告诉编译器,把两个字符串系在一起。

各个CRuntimeClass对象的内容指定以及连接工作最好也能神不知鬼不觉,于是定义IMPLEMENT_DYNAMIC宏:

#define   IMPLEMENT_DYNAMIC(class_name, base_class_name)  \

              _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name,0xFFFF,NULL)

#define  _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew)  \

               static  char  _lpsz##class_name[]  =  #class_name;  \

               CRuntimeClass  class_name::class##class_name  =   {  \

                             _lpsz##class_name,  sizeof(class_name),  wSchema,  pfnNew,  \

                                         RUNTIME_CLASS(base_class_name),  NULL};  \

      static  AFX_CLASSINIT   _init_##class_name(&class_name::class##class_name);  \

               CRuntimeClass*   class_name::GetRuntimeClass()   const  \

                   {return  &class_name::class##class_name;}  \

#define  RUNTIME_CLASS(class_name)  \

             (&class_name::class##class_name)

其中struct   AFX_CLASSINIT,定义如下:

struct   AFX_CLASSINIT

              {AFX_CLASSINIT(CRuntimeClass*   pNewClass);  };

这表示它有一个构造函数(C++的struct和class都有构造函数),定义如下:

CLASSINIT::CLASSINIT(CRuntimeClass*   pNewClass)

{

       pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;

       CRuntimeClass::pFirstClass = pNewClass;

}

此次构造负责linked list的连接工作

现在来看看这个例程:

class CView : public CWnd

{

      DELARE_DYNAMIC(CView)

      …

};

IMPLEMENT_DYNAMIC(CView, CWnd)

于是,程序中只需要简简单单的两个宏DELARE_DYNAMIC(Cxxx)和IMPLEMENT_DYNAMIC(Cxxx,Cxxxbase),就完成了构建数据并加入链表的工作:

image

但是链表的头要特别处理:

class  CObject

{

public:

     virtual   CRuntimeClass*   GetRuntimeClass()   const;

public:

    static  CRuntimeClass  classCObject;

};

  static   char szCObject[]  = “CObject”; 

  struct  CRuntimeClass  CObject::classCObject  =   { 

                             szCObject,  sizeof(CObject),  0xffff,  NULL,  NULL,  NULL}; 

  static  AFX_CLASSINIT   _initCObject(&CObject::classCObject); 

  CRuntimeClass*   class_name::GetRuntimeClass()   const 

                   {return  &CObject::classCObject;} 

  CRuntimeClass*   CRuntimeClass::pFirstClass  =  NULL;

整个“类别型录”链表的头部就形成了:

image

于是我们可以织出这样一张大网:

image

有了这张“类别型录”网,要实现IsKindOf功能,再轻松不过了:

1.为CObject加上一个IsKindOf函数,于是此函数将被所有类继承,它将把参数所指定的某个CRuntimeClass对象拿来与类别型录中的元素一一比较,比较成功,就传回TRUE,否则传回FALSE。

class  CObject

{

public:

BOOL  IsKindOf(const  CRuntimeClass*  pClass)  const;

};

BOOL  CObject::IsKindOf(const  CRuntimeClass*  pClass)  const

{

        CRuntimeClass*   pClassThis = GetRuntimeClass();

        while(pClassThis  !=  NULL)

        {

                 if(pClassThis  ==  pClass)   return TRUE;

                 pClassThis = pClassThis->m_pBaseClass;

        }

        return  FALSE;

}

 

4.Dynamic  Creation(动态创建)

我们可以把类的大小记录在类别型录中,把建构函数(不是构造函数)也记录在类别型录中,当程序在执行期获得一个类名称,它就可以在“类别型录网”中找出对应的元素,然后调用其建构函数,产生出对象。

于是CRuntimeClass变为:

struct CRuntimeClass

{

      LPCSTR  m_lpszClassName;

      int  m_nObjectSize;

      UINT   m_wSchema;     //schema  number  of  the  loaded  class

      CObect*  (PASCAL*  m_pfnCreateObject)();

      CRuntimeClass*   m_pBaseClass;            //基类

      CObject*  CreateObject();

      static  CRuntimeClass*  PASCAL  Load();

      static  CRuntimeClass *  pFirstClass;        

      CRuntimeClass*  m_pNextClass;         //下一个注册类

};

为了适应CRuntimeClass中新增的成员变量,我们再添两个宏,DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE:

#define  DECLARE_DYNCREATE(class_name)  \

               DECLARE_DYNAMIC(class_name)  \

               static  CObject*  PASCAL  CreateObject();

#define  IMPLEMENT_DYNCREATE(class_name, base_class_name)  \

               CObject*  PASCAL  class_name::CreateObject()  \

                               {return  new  class_name;}  \

               _IMPLEMENT_RUNTIMECLASS(class_name,  base_class_name,  0xFFF,  \

                               class_name::CreateObject)

以CFrameWnd为例:

class  CFrameWnd : public  CWnd

{

         DECLARE_DYNCREATE(CFrameWnd)

         …

};

IMPLEMENT_DYNCREATE(CFrameWnd,  Cwnd)

图示:

image

拥有动态创建能力的类库,必然拥有运行时类型识别能力。

现在开始仿真动态创建,首先在main函数中加上这段代码:

void  main()

{

CRuntimeClass*  pClassRef;

CObject*   pOb;

  while(1)

  {

      if((pClassRef  =  CRuntimeClass::Load())  ==  NULL)   break;

      pOb  =  pClassRef->CreateObject();

      if(pOb  !=  NULL)

                pOb->SayHello();

  }

}

并设计CRuntimeClass::CreateObject和CRuntimeClass::Load如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CObject *CRuntimeClass::CreateObject()
{
   If(m_pfnCreateObject==NULL)//不支持动态创建。
    {
        throw runtime_error("此类不支持动态创建");
        Return NULL;
    }
    CObject*pObject=(*m_pfnCreateObject)();
    Return pObject;
}

CRuntimeClass*PASCL CRuntimeClass::Load()
{
   Char szClassName[64];
   CRuntimeClass*pClass
   cout<<"输入一个类名:";
   cin>>szClassName;
   for(pClass=pFirstClass;pClass;pClass=pClass->m_pNextClass)
    {
       if(strcmp(szClassName,pClass->m_lpszClassName)==0)
               return pClass;
        return NULL;
    }
}

 

转载请标注来源:http://www.alonemonkey.com

By:AloneMonkey

本文链接:http://www.alonemonkey.com/mfc-three.html