MFC中RTTI 运行时类型识别 的模拟实现

                                              MFC中RTTI( 运行时类型识别 )的模拟实现

      在编程的过程中,我们经常要判断一个对象是否属于某个类型,这就是RTTI,运行时类型识别,在MFC中RTTI是怎么实现的呢,主要是借助于一个类CRuntimeClass,两个宏

DECLARE_DYNAMIC和 IMPLEMENT_DYNAMIC  .

        我们在每个类中加入一个CRuntimeClass对象,这些对象被用链表的形式链接起来,形成一个RTTI 网。

       DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC两个宏,前者实现的就是在类中加入CRuntimeClass对象,后者将它们链接起来。

       CRuntimeClass 是一个结构,其中包含类名称,下一个CRuntimeClass 的指针,以及static 的CRuntimeClass 链表头指针 等等。

1.       CRuntimeClass的定义模仿如下:

       struct   CRuntimeClass

      {

         LPCSTR   m_lpszClassName;//用来保存类的名称

         Int   m_nObjectSize;// 类对象的大小

         UINT  m_wschema;

         CObject   * (PASCAL  * pfnCreateObject) ();

         CRuntimeClass  * m_pBaseClass;  //指向基类的CRuntimeClass 的指针

       

         static  CRuntimeClass  * pFirstClass;  //静态成员,整个链表的头结点

         CRuntimeClass  * m_pNextClass;   //下一个 CRuntimeClass结点

       };

2.    DECLARE_DYNAMIC 的定义如下:

       #define    DECLARE_DYNAMIC(clss_name)/
       public:/
       static  CRuntimeClass  class##class_name;/
       virtual CRuntimeClass  * GetRuntimeClass()  const;

        这里##是个连接符,class##class_name表示在class_name前面加上字符class

        例如 :class##CView  则表示 classCView

        这个宏定义了两个东西:一个CRuntimeClass 的静态成员变量 class##class_name 

        一个GetRuntimeClass的虚函数,函数返回本类的CRuntimeClass * .    

3.   定义好了,现在就要实现并且链接起来,这就是IMPELEMENT_DYNAMIC 宏:

      #define     IMPELEMENT_DYNAMIC (class_name,base_class_name)/

      _IMPELEMENT_RUNTIMECLASS/   (class_name,base_class_name,0xFFFF,NULL)  

      _IMPELEMENT_RUNTIMECLASS 又是一个宏。它定义如下:

    

#define _IMPELEMENT_RUNTIMECLASS/ (class_name,base_class_name,wSchema,pfnNew)/

先定义一个包含类名字符串的字符数组

static    _lpsz##class_name[]=#class_name;

初始化 CRuntimeClass 成员结构体

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);/

实现类的GetRuntimeClass虚函数

CRuntimeClass * class_name::GetRuntimeClass() const/

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

重点在于AFX_CLASSINIT   ,它有一个构造函数,它定义如下:

        struct   AFX_CLASSINIT

{

    AFX_CLASSINIT(CRuntimeClass * pNewClass)

   {

       pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;

       CRuntimeClass::pFirstClass=pNewClass;

   }

}

哈哈,一个完美的前插入新结点到链表,这样整个链表就被链接建立起来了。

但是,链表的头需要特殊处理,所以CObject不能套用DECLARE_DYNAMIC和

IMPELEMENT_DYNAMIC  宏,它必须特殊处理如下:

 

class CObject

{

     public:

           CRuntimeClass *  GetRuntimeClass() const;

     .........

     public: 

     static   CRuntimeClass   classCObject;

     .........

};

CObject实现如下:

static  char  szCObject[]="CObject";

struct   CRuntimeClass   CObject::classCObject=

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

static  AFX_CLASSINIT  _init_CObject(&CObject::classCObject);

CRuntimeClass *  GetRuntimeClass() const

{

    return   &CObject::classCObject;

}

这里最主要的是,将CObject::classCObject的基类CRuntimeClass *设置为NULL,因为它本身就是基类。

最后,记得初始化整个链表的头指针:

  CRuntimeClass::pFirstClass=&CObject::classCObject;

让它指向CObject的CRuntimeClass对象。

那么有了这些,我们怎么来判断一个对象是否属于某个类型呢?

我们为CObject类加上一个IsKindOf方法,这样所有的子类都会继承这个方法:

class  CObject

{

public:

   ........

   BOOL  IsKindOf(const  CRuntimeClass  *  pClass)

   {

       //首先获得类本身的CRuntimeClass

       CRuntimeClass  *pClassThis=GetRuntimeClass();

      //然后逆流而上查找基类,查找是否有CRuntimeClass跟传入参数相同,如是,则说明是属于此类型

      while(pClassThis!=NULL)

     {

          if(pClassThis==pClass)

          {

             return  TRUE;

          }

         pClassThis=pClassThis->m_pBaseClass;

     }

      return  FALSE;

   }

}

这样我们就可以以如下方式来进行RTTI ,运行时类型识别:

#define    RUNTIME_CLASS(class_name) /

       & class_name::class##class_name;

CView  * pView=new  CView;

pView->IsKindOf(RUNTIME_CLASS(CView));   应该是TRUE

pView->IsKindOf(RUNTIME_CLASS(CWnd));    应该是TRUE

pView->IsKindOf(RUNTIME_CLASS(CDocument)); 应该是FALSE

至此,RTTI 的模拟到此结束,虽然整个过程都是深入浅出中描述的,但是自己单独把这个过程给描述出来,直接增加了对RTTI的理解深度。

下一篇博客,动态创建,也是基于RTTI的结果。

    

        

       

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值