Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1495877
  • 博文数量: 218
  • 博客积分: 6394
  • 博客等级: 准将
  • 技术积分: 2563
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-08 15:33
个人简介

持之以恒

文章分类

全部博文(218)

文章存档

2013年(8)

2012年(2)

2011年(21)

2010年(55)

2009年(116)

2008年(16)

分类:

2009-08-27 09:18:15

1.
核心类CRuntimeClass.
struct CRuntimeClass//部分字段和方法
{
        // Attributes
        LPCSTR m_lpszClassName;
        int m_nObjectSize;
        CObject *(PASCAL* m_pfnCreateObject)();
        CRuntimeClass* m_pBaseClass;

        CObject* CreateObject();
        static CRuntimeClass* PASCAL Load();

        // CRuntimeClass objects linked together in simple list
        static CRuntimeClass* pFirstClass; // start of class list
        CRuntimeClass* m_pNextClass; // linked list of registered
//classes
};

CRuntimeClass的关键字段:

1.1 m_lpszClassName:
类型名,所有实现RTTI的类都要通过这个名称来创建对象.
如要待创建类CObject,则应在CObject中创建CRuntimeClass类的对象,对象的名称为classCObject,classCObject的m_lpszClassName字段值为
CObject。

1.2 m_pfnCreateObject:
函数指针, 其声明为: CObject *(PASCAL* m_pfnCreateObject)(); 其对应的函数的形式是:返回值是
CObject *,函数的参数为空。

1.3 CreateObject()函数
声明为: CObject* CreateObject();

1.4 pFirstClass 和 m_pNextClass
声明为:
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass;

注意: pFirstClass被声明为static,因为这个属性在编译的时候就要被赋初值
而m_pNextClass是非static的

CRuntimeClass通过这2个属性来构建出所有支持的类型链表。

------------------------- 举例 ---------------------------------
假如要创建一个类Ca,必须从CObject继承.
2.
在类Ca中加入一个CRuntimeClass类型的静态成员变量classCa (变量名称必须依据命名规范 class + 类名):(为什么:因为宏的定义是这么进行定义的!)
      public: static CRuntimeClass classCa;

3.
把classCa成员变量的指针加入到CRuntime的类链表中(该类链表中的元素都从CRuntime继承)。
4.
初始化静态变量classCa:
      CRuntimeClass Ca::classCa = {
          "_lpszCa",
          sizeof(Ca),
          0xFFFF,
          Ca::CreateObject, //函数指针, classCa的m_pfnCreateObject成员变量的值被指定为Ca::CreateObject。NULL 表示Ca是虚类
          (&CObject::classCObject),
          0
       };      
5.
   在CRuntimeClass中定义一个Load函数,其功能是根据参数在CRuntimeClass的类链表中查找是否存在这个类,如果存在,则返回这个类指针

CRuntimeClass* * CRuntimeClass::Load( char szClassName ){
   CRuntimeClass* pClass;
   for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
    {
        if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
            return pClass;
    }
    //类链表中没有这个类
    return NULL;
}
6.
调用Load函数,并把参数设为"classCa"
CRuntimeClass* pClassRef;
pClassRef = CRuntimeClass::Load();
//本例得到得是Ca中静态成员变量classCa 得指针。

然后调用classCa的 CreateObject()函数
CObject* pOb;
pOb = pClassRef->CreateObject();
pOb->doSomething();

核心宏:
所有的类型
声明和定义都是通过宏来实现的,无法通过函数来实现,因为所有的类型必须在编译的时候就确定下来。
这些宏可以分为2类:

1. 构建CRuntimeClass中类型链表的宏

1.1 DECLARE_DYNAMIC(class_name):

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

1.2 IMPLEMENT_DYNAMIC(class_name, base_class_name)

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

注意 _IMPLEMENT_RUNTIMECLASS又是一个宏!在下面有其相应的说明


2. 通过类型名称创建类的宏

2.1 DECLARE_DYNCREATE(class_name)

#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \   //注意这个和上面的是一样的吧,说明使用了宏嵌套
static CObject* PASCAL CreateObject();

2.2 IMPLEMENT_DYNCREATE(class_name, base_class_name)

#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)

注意:第二类宏(通过类型名称创建类的宏)包含了对应的第一类宏(declare和 implement),所以,如果用了第二类宏,就不需要再用第一类宏了。
也即: 如果用了第二类宏来申明和实现类的动态创建,则自动完成了动态类链表的创建。

但是,如果某些动态类是不能创建的,只能申明,则只要使用第一类宏。比如一下虚类(如CObject(它是很多具体类的父类)),在CRuntimeClass的类链表中存在这个类,但是不能创建它,因为对它没有使用第二类宏(即它没有CreateObject函数)。

3. 另一个重要的宏_IMPLEMENT_RUNTIMECLASS
在IMPLEMENT_DYNAMIC和IMPLEMENT_DYNCREATE宏中,都调用了宏_IMPLEMENT_RUNTIMECLASS,但是对于最好一个参数(表示createobject的函数指针)使用了不同的参数值().
IMPLEMENT_DYNAMIC 使用NULL, IMPLEMENT_DYNCREATE宏使用class_name::CreateObject.
NULL 表示没有createobject函数的实现, 也表示了对应的类是一个虚类。
_IMPLEMENT_RUNTIMECLASS宏的定义(很负责,其实它才是真正的核心宏):

#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); //上面这个
AFX_CLASSINIT类型的变量完成了单链表的建立!
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return &class_name::class##class_name; } \

其中含有一个 静态的类(structure)AFX_CLASSINIT的实例对象,由这个对象的构造函数来把类型链表串起来.
AFX_CLASSINIT的申明和定义如下:

struct AFX_CLASSINIT
{
    AFX_CLASSINIT(CRuntimeClass* pNewClass);
};

AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
{
    pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
    CRuntimeClass::pFirstClass = pNewClass;
}


//-----------------------------------------------------
重点总结:
    功能是通过宏来实现的
    基本上所有的变量都是static,
    要定义好类的命名规范,这是宏能正确达到预定功能的前提。


//------------------------------------------------------
阅读(1241) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~