假设需要一个类别库,改类别库共包含以下5个类:GrandFather(祖父类)、Father(父类)、Son(儿子类)、Daughter(女儿类)、GrandSon(孙子类)
各个类之间的继承关系为:
相应的代码为:
class GrandFather { }; class Father:public GrandFather { }; class Son:public Father { }; class Daughter:public Father { }; class GrandSon:public Son { };
想要让该类别库具备IsKindOf的功能,即能在执行时期侦测某个对象是否“属于某个类别”,并传回TRUE或FALSE。
希望实现如下效果:
GrandFather* pGrandSon = new GrandSon; cout << pGrandSon->IsKindof(GrandFather); //应该输出1 cout << pGrandSon->IsKindof(Father); //应该输出1 cout << pGrandSon->IsKindof(Son); //应该输出1 cout << pGrandSon->IsKindof(Daughter); //应该输出0
设计思路:
以
pGrandSon->IsKindof(GrandFather)
为例,想要在运行时判断:GrandSon 类是否是 GrandFather的子类。
我们知道,GrandSon类的继承路线是这样的:GrandSon--->Son--->Father--->GrandFather,因此GrandSon是GrandFather的子类。
所以我们在进行判断的时候,需要从GrandSon类的父类进行找起,然后一级级的往上找,然后判断某个父类是否为:GrandFather。
换句话说,想要判断GrandSon是否是GrandFather的子类,需要“有迹可循”。
以上的“迹”,我们可以通过一个结构体:CRuntimeClass,来进行保存。
该结构体至少需要保存如下信息:类别名称、串行的Next 指针,以及串行的First 指针。
First指针属于全域变量,一份就好,所以应该是static变量。
struct CRuntimeClass { LPCSTR m_lpszClassName; int m_nObjectSize; UINT m_wSchema; GrandFather* (PASCAL* m_pfnCreateObject)(); CRuntimeClass* m_pBaseClass; static CRuntimeClass* pFirstClass; CRuntimeClass* m_pNextClass; };
要实现IsKindOf()的功能,则类别库中的5个类(GrandFather、Father、Son、Daughter、GrandSon)都应该各拥有一个CRuntimeClass成员变量。
进一步将类修改如下:
struct CRuntimeClass { LPCSTR m_lpszClassName; static CRuntimeClass* pFirstClass; CRuntimeClass* m_pNextClass; CRuntimeClass* m_pBaseClass; }; class GrandFather { public: static CRuntimeClass classGrandFather; virtual CRuntimeClass* GetRuntimeClass() const{return &GrandFather::classGrandFather;} }; class Father:public GrandFather { public: static CRuntimeClass classFather; virtual CRuntimeClass* GetRuntimeClass() const{ return &Father::classFather;} }; class Son:public Father { public: static CRuntimeClass classSon; virtual CRuntimeClass* GetRuntimeClass() const { return &Son::classSon; } }; class Daughter:public Father { public: static CRuntimeClass classDaughter; virtual CRuntimeClass* GetRuntimeClass() const { return &Daughter::classDaughter; } }; class GrandSon:public Son { public: static CRuntimeClass classGrandSon; virtual CRuntimeClass* GetRuntimeClass() const { return &GrandSon::classGrandSon; } };
其中,GetRuntimeClass为内联虚函数,作用为:获取当前对象所属类的 「成员变量类型为CRuntimeClass」的成员变量地址。
如:
CRuntimeClass* GrandSon::GetRuntimeClass() const { return &GrandSon::classGrandSon; }
返回成员变量classGrandSon的内存地址
接下来,需要完成最重要的一步:填充各个类中CRuntimeClass结构体的数据内容。
//祖父 static char szGrandFather[] = "GrandFather"; CRuntimeClass GrandFather::classGrandFather = { szGrandFather}; //父亲 static char _lpszFather[] = "Father"; CRuntimeClass Father::classFather = {_lpszFather, NULL ,&GrandFather::classGrandFather}; //儿子 static char _lpszSon[] = "Son"; CRuntimeClass Son::classSon = {_lpszSon,NULL ,&Father::classFather }; //女儿 static char _lpszDaughter[] = "Daughter"; CRuntimeClass Daughter::classDaughter = {_lpszDaughter,NULL ,&Father::classFather}; //孙子 static char _lpszGrandSon[] = "GrandSon"; CRuntimeClass GrandSon::classGrandSon = {_lpszGrandSon, NULL ,&Son::classSon};
以上代码将填充CRuntimeClass结构体的
LPCSTR m_lpszClassName(类名)、CRuntimeClass* m_pBaseClass(基类的CRuntimeClass结构地址)。
另外,还有2个成员变量需要进行初始化:pFirstClass和m_pNextClass
pFirstClass是静态的,需要初始化为NULL:CRuntimeClass* CRuntimeClass::pFirstClass = NULL;
m_pNextClass的初始化操作,可以通过以下的结构体构造函数来完成:
在ClassFile.h头文件中,增加如下代码:
struct AFX_CLASSINIT { AFX_CLASSINIT(CRuntimeClass* pNewClass) { pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass; } };
以上代码定义了一个结构体:AFX_CLASSINIT,并在结构体的构造函数中(C++中结构体也是有构造函数的……)对m_pNextClass 和 pFirstClass进行赋值。
在通初始化结构体的其他成员变量一样,需要我们手动在ClassFile.cpp文件中添加初始化另外几个成员变量的代码:
//祖父 static AFX_CLASSINIT _init_GrandFather(&GrandFather::classGrandFather); //父亲 static AFX_CLASSINIT _init_Father(&Father::classFather); //儿子 static AFX_CLASSINIT _init_Son(&Son::classSon); //女儿 static AFX_CLASSINIT _init_Daughter(&Daughter::classDaughter); //孙子 static AFX_CLASSINIT _init_GrandSon(&GrandSon::classGrandSon);
当执行以上代码的时候,将把各个类中的CRuntimeClass结构体串联起来。
这样,经过以上的步骤,整个类别库表就构造好了!类似下图所示:
BOOL GrandFather::IsKindof(const CRuntimeClass* pClass)const { CRuntimeClass* pClassThis = GetRuntimeClass(); while(pClassThis != NULL) { if (pClassThis == pClass) return TRUE; pClassThis = pClassThis->m_pBaseClass; } return FALSE; }接着,就可以在main函数中进行调用了:
void main() { GrandFather* pGrandSon = new GrandSon; cout << "pGrandSon->IsKindOf(RUNTIME_CLASS(GrandFather)) "<< pGrandSon->IsKindof(&GrandFather::classGrandFather)<< "\n"; cout << "pGrandSon->IsKindOf(RUNTIME_CLASS(Father)) "<< pGrandSon->IsKindof(&Father::classFather)<< "\n"; cout << "pGrandSon->IsKindOf(RUNTIME_CLASS(Son)) "<< pGrandSon->IsKindof(&Son::classSon) << "\n"; cout << "pGrandSon->IsKindOf(RUNTIME_CLASS(Daughter)) "<< pGrandSon->IsKindof(&Daughter::classDaughter) << "\n"; delete pGrandSon; getchar(); }执行结果如下: